@metasession.co/devaudit-cli 0.1.58 → 0.1.59

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/dist/index.js CHANGED
@@ -56,7 +56,7 @@ function emitJsonResult(payload) {
56
56
 
57
57
  // package.json
58
58
  var package_default = {
59
- version: "0.1.58"};
59
+ version: "0.1.59"};
60
60
 
61
61
  // src/lib/version.ts
62
62
  var CLI_VERSION = package_default.version;
@@ -521,6 +521,7 @@ async function runAuthStatus() {
521
521
  }
522
522
  var FRAMEWORK_FILES = [
523
523
  "INSTRUCTIONS.md",
524
+ "AGENTS.md",
524
525
  "CLAUDE.md",
525
526
  ".cursorrules",
526
527
  ".windsurfrules",
@@ -596,11 +597,16 @@ async function runStatus(options) {
596
597
  }
597
598
  var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
598
599
  var DEFAULT_MAX_ATTEMPTS = 5;
600
+ var DEFAULT_UPLOAD_MAX_TIME_SECONDS = 120;
599
601
  var INITIAL_BACKOFF_MS = 1e3;
600
602
  function maxAttempts() {
601
603
  const raw = Number.parseInt(process.env["UPLOAD_MAX_ATTEMPTS"] ?? "", 10);
602
604
  return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_MAX_ATTEMPTS;
603
605
  }
606
+ function uploadMaxTimeSeconds() {
607
+ const raw = Number(process.env["UPLOAD_MAX_TIME_SECONDS"] ?? "");
608
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_UPLOAD_MAX_TIME_SECONDS;
609
+ }
604
610
  async function collectFiles(filePath) {
605
611
  const stat = await promises.stat(filePath);
606
612
  if (stat.isFile()) return [filePath];
@@ -626,6 +632,30 @@ function isUneditedStub(buf) {
626
632
  function delay(ms) {
627
633
  return new Promise((res) => setTimeout(res, ms));
628
634
  }
635
+ function buildUploadForm(file, buf, opts) {
636
+ const form = new FormData();
637
+ const blob = new Blob([new Uint8Array(buf)]);
638
+ form.set("file", blob, basename(file));
639
+ form.set("projectSlug", opts.projectSlug);
640
+ form.set("requirementId", opts.requirementId);
641
+ form.set("evidenceType", opts.evidenceType);
642
+ form.set("metadata", JSON.stringify(opts.metadata ?? {}));
643
+ if (opts.releaseVersion) form.set("releaseVersion", opts.releaseVersion);
644
+ if (opts.createReleaseIfMissing) form.set("createReleaseIfMissing", "true");
645
+ if (opts.environment) form.set("environment", opts.environment);
646
+ if (opts.evidenceCategory) form.set("evidenceCategory", opts.evidenceCategory);
647
+ if (opts.releaseBranch) form.set("releaseBranch", opts.releaseBranch);
648
+ if (opts.releaseTitle) form.set("releaseTitle", opts.releaseTitle);
649
+ if (opts.changeType) form.set("changeType", opts.changeType);
650
+ if (opts.gateStatus) form.set("gateStatus", opts.gateStatus);
651
+ return form;
652
+ }
653
+ function uploadFailureMessage(err, timeoutSeconds) {
654
+ if (err instanceof Error && err.name === "AbortError") {
655
+ return `upload timed out after ${timeoutSeconds}s`;
656
+ }
657
+ return err instanceof Error ? err.message : String(err);
658
+ }
629
659
  async function probeBaseUrlDrift(baseUrl) {
630
660
  try {
631
661
  const probeUrl = `${baseUrl.replace(/\/$/, "")}/api/health`;
@@ -650,30 +680,33 @@ async function probeBaseUrlDrift(baseUrl) {
650
680
  }
651
681
  async function uploadOne(file, buf, opts) {
652
682
  const attempts = maxAttempts();
653
- const form = new FormData();
654
- const blob = new Blob([new Uint8Array(buf)]);
655
- form.set("file", blob, basename(file));
656
- form.set("projectSlug", opts.projectSlug);
657
- form.set("requirementId", opts.requirementId);
658
- form.set("evidenceType", opts.evidenceType);
659
- form.set("metadata", JSON.stringify(opts.metadata ?? {}));
660
- if (opts.releaseVersion) form.set("releaseVersion", opts.releaseVersion);
661
- if (opts.createReleaseIfMissing) form.set("createReleaseIfMissing", "true");
662
- if (opts.environment) form.set("environment", opts.environment);
663
- if (opts.evidenceCategory) form.set("evidenceCategory", opts.evidenceCategory);
664
- if (opts.releaseBranch) form.set("releaseBranch", opts.releaseBranch);
665
- if (opts.releaseTitle) form.set("releaseTitle", opts.releaseTitle);
666
- if (opts.changeType) form.set("changeType", opts.changeType);
667
- if (opts.gateStatus) form.set("gateStatus", opts.gateStatus);
683
+ const timeoutSeconds = uploadMaxTimeSeconds();
668
684
  const url = `${opts.baseUrl.replace(/\/$/, "")}/api/evidence/upload`;
669
685
  let attempt = 1;
670
686
  let backoff = INITIAL_BACKOFF_MS;
671
687
  while (attempt <= attempts) {
672
- const res = await fetch(url, {
673
- method: "POST",
674
- headers: { authorization: `Bearer ${opts.apiKey}` },
675
- body: form
676
- });
688
+ const controller = new AbortController();
689
+ const timer = setTimeout(() => controller.abort(), timeoutSeconds * 1e3);
690
+ let res;
691
+ try {
692
+ res = await fetch(url, {
693
+ method: "POST",
694
+ headers: { authorization: `Bearer ${opts.apiKey}` },
695
+ body: buildUploadForm(file, buf, opts),
696
+ signal: controller.signal
697
+ });
698
+ } catch (err) {
699
+ const error = uploadFailureMessage(err, timeoutSeconds);
700
+ if (attempt < attempts) {
701
+ await delay(backoff);
702
+ backoff *= 2;
703
+ attempt += 1;
704
+ continue;
705
+ }
706
+ return { file, ok: false, status: 0, error };
707
+ } finally {
708
+ clearTimeout(timer);
709
+ }
677
710
  if (res.ok) {
678
711
  const body = await res.json().catch(() => null);
679
712
  return { file, ok: true, status: res.status, body };
@@ -1694,6 +1727,18 @@ This file provides guidance to Gemini CLI when working in this repository.
1694
1727
 
1695
1728
  Please adhere to the instructions in \`INSTRUCTIONS.md\` as the **Single Source of Truth**.
1696
1729
  `;
1730
+ var AGENTS_POINTER = `# AGENTS.md
1731
+
1732
+ This file provides guidance to Codex and AGENTS-compatible coding agents when working in this repository.
1733
+
1734
+ ## Project Standards
1735
+
1736
+ All project rules, architectural standards, and development workflows are consolidated in:
1737
+
1738
+ - [INSTRUCTIONS.md](./INSTRUCTIONS.md)
1739
+
1740
+ Read and follow \`INSTRUCTIONS.md\` as the single source of truth. When working through an SDLC stage, also read the relevant workflow file in \`SDLC/\`.
1741
+ `;
1697
1742
  var CLAUDE_POINTER_TAIL = `
1698
1743
  ## Project Standards
1699
1744
 
@@ -1754,9 +1799,10 @@ async function syncAiRules(ctx) {
1754
1799
  await writePointerFile(join(ctx.projectPath, ".cursorrules"), CURSOR_POINTER);
1755
1800
  await writePointerFile(join(ctx.projectPath, ".windsurfrules"), WINDSURF_POINTER);
1756
1801
  await writePointerFile(join(ctx.projectPath, "GEMINI.md"), GEMINI_POINTER);
1802
+ await writePointerFile(join(ctx.projectPath, "AGENTS.md"), AGENTS_POINTER);
1757
1803
  await updateClaudeFile(join(ctx.projectPath, "CLAUDE.md"));
1758
1804
  await updateInstructionsFile(join(ctx.projectPath, "INSTRUCTIONS.md"), sdlcContent);
1759
- return { name: "AI rule pointers + INSTRUCTIONS.md", filesSynced: 5, message: "synced" };
1805
+ return { name: "AI rule pointers + INSTRUCTIONS.md", filesSynced: 6, message: "synced" };
1760
1806
  }
1761
1807
  async function syncStackHooks(ctx) {
1762
1808
  const adapter = await loadStackAdapter(ctx.installerRoot, ctx.stack);