failproofai 1.0.2-beta.4 → 1.0.2-beta.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.
Files changed (147) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +5 -5
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +2 -2
  6. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  12. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +2 -2
  15. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  16. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
  20. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  21. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +13 -13
  22. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  23. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -4
  25. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -1
  32. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/audit/page/build-manifest.json +2 -2
  34. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  35. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  37. package/.next/standalone/.next/server/app/index.html +1 -1
  38. package/.next/standalone/.next/server/app/index.rsc +14 -14
  39. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
  40. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
  41. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  42. package/.next/standalone/.next/server/app/page/build-manifest.json +2 -2
  43. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  44. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  46. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +2 -2
  47. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  48. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  50. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +2 -2
  51. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  52. package/.next/standalone/.next/server/app/project/[name]/page.js +2 -2
  53. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  54. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  55. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +2 -2
  56. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  57. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  58. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +2 -2
  59. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  60. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  61. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +2 -2
  62. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  63. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  64. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  65. package/.next/standalone/.next/server/app/settings/page/build-manifest.json +2 -2
  66. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
  67. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  68. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  69. package/.next/standalone/.next/server/chunks/[root-of-the-server]__03r-lqq._.js +3 -0
  70. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  71. package/.next/standalone/.next/server/chunks/[root-of-the-server]__12021ot._.js +3 -0
  72. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1le9jqc._.js +3 -0
  73. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0clqfab._.js → [root-of-the-server]__1zkek3z._.js} +2 -2
  74. package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/{_1lbh81u._.js → _12moi5-._.js} +1 -1
  76. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +5 -5
  77. package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +1 -1
  78. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  79. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1m84s36._.js → [root-of-the-server]__00-s7h8._.js} +1 -1
  80. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +2 -2
  81. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +2 -2
  82. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +2 -2
  83. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__07gm3zl._.js +3 -3
  84. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +2 -2
  85. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +2 -2
  86. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
  87. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +2 -2
  88. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +2 -2
  89. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__14muoc4._.js → [root-of-the-server]__0stn0gx._.js} +2 -2
  90. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0jzbk4_._.js → [root-of-the-server]__190won8._.js} +1 -1
  91. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ctpynv._.js +1 -1
  92. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +2 -2
  93. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0rsd3ll._.js → [root-of-the-server]__1sc84bb._.js} +2 -2
  94. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  95. package/.next/standalone/.next/server/chunks/ssr/_1ddpc5g._.js +1 -1
  96. package/.next/standalone/.next/server/chunks/ssr/{_1db3-8n._.js → _1if9ixi._.js} +2 -2
  97. package/.next/standalone/.next/server/chunks/ssr/{_1dkh76z._.js → _1kesqs-._.js} +2 -2
  98. package/.next/standalone/.next/server/chunks/ssr/{_0ovx4lz._.js → _1km9-gn._.js} +1 -1
  99. package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +1 -1
  100. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  101. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  102. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  103. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  104. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
  105. package/.next/standalone/.next/server/chunks/ssr/lib_1cf5ya2._.js +3 -0
  106. package/.next/standalone/.next/server/chunks/ssr/lib_opencode-projects_ts_15bjxkm._.js +1 -1
  107. package/.next/standalone/.next/server/middleware-build-manifest.js +5 -5
  108. package/.next/standalone/.next/server/pages/404.html +1 -1
  109. package/.next/standalone/.next/server/pages/500.html +1 -1
  110. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  111. package/.next/standalone/.next/server/server-reference-manifest.json +19 -19
  112. package/.next/standalone/.next/static/chunks/{0lshnlpy1m6bc.js → 0tyt-3a5rtzy8.js} +1 -1
  113. package/.next/standalone/.next/static/chunks/{0ds64uculrze8.js → 21r7iw3rmixf5.js} +1 -1
  114. package/.next/standalone/.next/static/chunks/{07j2u70_3qsx8.js → 26lfjhb2kzzgb.js} +1 -1
  115. package/.next/standalone/.next/static/chunks/{2dbi_x0c8n8fi.js → 2_27jraat038x.js} +1 -1
  116. package/.next/standalone/.next/static/chunks/{0d_re32wscs0b.js → 2hwc8e923g5df.js} +1 -1
  117. package/.next/standalone/.next/static/chunks/{1q76jk_1_wgjq.js → 33np9nrh1mvj9.js} +1 -1
  118. package/.next/standalone/.next/static/chunks/{0k_yvjc1yz0pq.js → 36-8i_vbkh85w.js} +1 -1
  119. package/.next/standalone/.next/static/chunks/{1o0ahew9568ls.js → 391tpdqcas7rq.js} +1 -1
  120. package/.next/standalone/.next/static/chunks/{00_t-xvc59tkb.js → 3_b73tc78jwsq.js} +1 -1
  121. package/.next/standalone/.next/static/chunks/{1oz0svxwt9574.js → 3i8rg2fv9nd6e.js} +2 -2
  122. package/.next/standalone/.next/static/chunks/{2817_8e94ah9z.js → 3jqm8ubpv3i-4.js} +1 -1
  123. package/.next/standalone/.next/static/chunks/{turbopack-17utl_jw0wj11.js → turbopack-2x-o099q64i8h.js} +1 -1
  124. package/.next/standalone/lib/opencode-db.ts +77 -0
  125. package/.next/standalone/lib/opencode-projects.ts +37 -41
  126. package/.next/standalone/lib/opencode-sessions.ts +59 -36
  127. package/.next/standalone/package.json +9 -9
  128. package/.next/standalone/server.js +1 -1
  129. package/bin/failproofai.mjs +24 -9
  130. package/dist/cli.mjs +734 -382
  131. package/dist/worker.mjs +179 -164
  132. package/lib/opencode-db.ts +77 -0
  133. package/lib/opencode-projects.ts +37 -41
  134. package/lib/opencode-sessions.ts +59 -36
  135. package/package.json +9 -9
  136. package/src/audit/cache.ts +167 -11
  137. package/src/audit/cli-adapters/claude.ts +111 -1
  138. package/src/audit/cli-adapters/index.ts +31 -1
  139. package/src/audit/index.ts +131 -11
  140. package/src/hooks/manager.ts +50 -3
  141. package/src/hooks/pack-cli.ts +237 -11
  142. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1l-khtb._.js +0 -3
  143. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1mhmdzs._.js +0 -3
  144. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qxztj-._.js +0 -3
  145. /package/.next/standalone/.next/static/{0iNzkTsP6rh14Rj5WL17o → 59jsH11LoyXu9UBoHvgGM}/_buildManifest.js +0 -0
  146. /package/.next/standalone/.next/static/{0iNzkTsP6rh14Rj5WL17o → 59jsH11LoyXu9UBoHvgGM}/_clientMiddlewareManifest.js +0 -0
  147. /package/.next/standalone/.next/static/{0iNzkTsP6rh14Rj5WL17o → 59jsH11LoyXu9UBoHvgGM}/_ssgManifest.js +0 -0
@@ -6,10 +6,10 @@
6
6
  * This layer decides nothing; it formats.
7
7
  */
8
8
  import { execFileSync } from "node:child_process";
9
- import { homedir } from "node:os";
9
+ import { homedir, tmpdir } from "node:os";
10
10
  import { createHash } from "node:crypto";
11
- import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
12
- import { resolve } from "node:path";
11
+ import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
12
+ import { basename, dirname, join, resolve } from "node:path";
13
13
  import { INTEGRATION_TYPES } from "./types";
14
14
  import { PACK_VERSION_RE } from "./pack-manifest";
15
15
  import { detectInstalledClis } from "./integrations";
@@ -354,6 +354,15 @@ export async function runPolicyPicker(
354
354
  * policy that already RUNS and already blocks something real, so the first
355
355
  * action is editing a working thing rather than authoring an empty one.
356
356
  */
357
+ /**
358
+ * A policy filename, whatever spelling it arrived in. Discovery takes
359
+ * `.mjs`/`.js`/`.ts` and nothing else, so a name with no extension has to gain
360
+ * one or the file it names can never be found.
361
+ */
362
+ function withPolicyExtension(name: string): string {
363
+ return /\.(mjs|js|ts)$/.test(name) ? name : `${name}.mjs`;
364
+ }
365
+
357
366
  async function scaffold(target: string | null): Promise<PackCliResult> {
358
367
  // Ask what the pack is called when nothing was named and there is somebody to
359
368
  // ask. The answer becomes the FILENAME and the header, so what lands on disk
@@ -374,9 +383,14 @@ async function scaffold(target: string | null): Promise<PackCliResult> {
374
383
  stdout: process.stdout,
375
384
  });
376
385
  if (answer === null) return ok(["Nothing written."]);
377
- chosen = `./${answer.trim().replace(/\.(mjs|js|ts)$/, "")}.mjs`;
386
+ chosen = answer.trim();
378
387
  }
379
- const path = resolve(chosen ?? "./my-policies.mjs");
388
+ // Both paths land here, because only one of them used to. A name typed at
389
+ // the prompt got `.mjs`; the same name passed as `--init myguards` was taken
390
+ // literally and wrote a file called `myguards` — which discovery skips (it
391
+ // takes .mjs/.js/.ts) and which no ESM loader will import. The starter file
392
+ // was unreachable by every command meant to pick it up.
393
+ const path = resolve(withPolicyExtension(chosen ?? "my-policies"));
380
394
  if (existsSync(path)) {
381
395
  return fail([`${path} already exists — name a different file, or edit that one.`]);
382
396
  }
@@ -416,7 +430,7 @@ customPolicies.add({
416
430
  " then ask your agent to force-push — it gets refused",
417
431
  "",
418
432
  "Then publish it:",
419
- ` failproofai publish ${path} --repo <you>/<repo> --version 1.0.0`,
433
+ " failproofai publish --repo <you>/<repo>",
420
434
  ]);
421
435
  }
422
436
 
@@ -582,6 +596,7 @@ async function ensureRepo(
582
596
  name: string,
583
597
  id: string,
584
598
  token: string,
599
+ sourceDir?: string,
585
600
  ): Promise<{ info: Awaited<ReturnType<typeof gh>>; created: boolean } | { error: string[] }> {
586
601
  let info = await gh(`${GITHUB_API}/repos/${owner}/${name}`, token);
587
602
  let created = false;
@@ -601,7 +616,15 @@ async function ensureRepo(
601
616
  name,
602
617
  private: false,
603
618
  description: `failproofai policy pack — ${id}`,
604
- auto_init: true,
619
+ // NOT auto_init. The author already has the commit that holds these
620
+ // policies; a repository seeded with its own "Initial commit" shares
621
+ // no history with it, so the `git push` that every publish is followed
622
+ // by is rejected as unrelated — and the way out (`pull --allow-
623
+ // unrelated-histories`, or a force-push over the seed) is a worse
624
+ // first five minutes than an empty repository, which accepts the push
625
+ // as-is. Releases do not need a commit to hang from: the tag is
626
+ // created against whatever the release API is given.
627
+ auto_init: false,
605
628
  }),
606
629
  });
607
630
  if (made.status >= 400) {
@@ -617,6 +640,14 @@ async function ensureRepo(
617
640
  };
618
641
  }
619
642
  created = true;
643
+ // A repository created with no commits has no default branch, and the
644
+ // release API tags the default branch — so something has to land on it
645
+ // before the release is cut. Pushing the author's own history is the
646
+ // version that leaves a usable repository behind; seeding is the fallback
647
+ // for a pack that is not in a git checkout at all.
648
+ if (!(sourceDir && pushExistingHistory(sourceDir, owner, name, token))) {
649
+ await seedDefaultBranch(owner, name, id, token);
650
+ }
620
651
  info = await gh(`${GITHUB_API}/repos/${owner}/${name}`, token);
621
652
  }
622
653
  if (info.status >= 400) {
@@ -625,6 +656,102 @@ async function ensureRepo(
625
656
  return { info, created };
626
657
  }
627
658
 
659
+ /**
660
+ * Push the checkout the policies live in to the repository just created for
661
+ * them, and report whether it landed.
662
+ *
663
+ * Why publish pushes at all: it created the repository, so it owns the one
664
+ * moment when pushing cannot conflict with anything. The repository used to be
665
+ * created with `auto_init`, which meant GitHub wrote an "Initial commit" the
666
+ * author did not have — so the `git push` that every publish is followed by was
667
+ * rejected as unrelated history, every time, for everybody. Seeding it and
668
+ * pushing it are the same job; doing only the first left the author to
669
+ * reconcile two histories by hand.
670
+ *
671
+ * It also makes the tag mean something. The release tags the default branch, so
672
+ * against a seeded repository `1.0.0` named a README commit that did not
673
+ * contain a single one of the policies it shipped.
674
+ *
675
+ * The token goes in through GIT_ASKPASS, never in the URL or the argv: a remote
676
+ * with a credential in it is written into `.git/config` in plaintext, and one on
677
+ * a command line is readable from `ps` by every user on the box.
678
+ */
679
+ export const __pushExistingHistoryForTest = (
680
+ dir: string,
681
+ owner: string,
682
+ name: string,
683
+ token: string,
684
+ ): boolean => pushExistingHistory(dir, owner, name, token);
685
+
686
+ function pushExistingHistory(dir: string, owner: string, name: string, token: string): boolean {
687
+ const git = (args: string[], env?: Record<string, string>): string | null => {
688
+ try {
689
+ return execFileSync("git", args, {
690
+ cwd: dir,
691
+ encoding: "utf8",
692
+ stdio: ["ignore", "pipe", "ignore"],
693
+ timeout: 60_000,
694
+ env: env ? { ...process.env, ...env } : process.env,
695
+ }).trim();
696
+ } catch {
697
+ return null;
698
+ }
699
+ };
700
+ const branch = git(["rev-parse", "--abbrev-ref", "HEAD"]);
701
+ // No commits yet (`HEAD` unborn) means there is nothing to push and nothing
702
+ // to conflict with later either.
703
+ if (!branch || branch === "HEAD" || !git(["rev-parse", "--verify", "HEAD"])) return false;
704
+
705
+ const askpass = join(mkdtempSync(join(tmpdir(), "fpai-askpass-")), "askpass.sh");
706
+ try {
707
+ writeFileSync(askpass, `#!/bin/sh\ncase "$1" in\n*Username*) echo x-access-token ;;\n*) echo "$FPAI_GH_TOKEN" ;;\nesac\n`, { mode: 0o700 });
708
+ const env = { GIT_ASKPASS: askpass, FPAI_GH_TOKEN: token, GIT_TERMINAL_PROMPT: "0" };
709
+ const url = `${GITHUB_GIT}/${owner}/${name}.git`;
710
+ // Name the remote FIRST when there is not one, so the push can be `-u` and
711
+ // leave the branch tracking it. Pushing to a bare URL and setting the
712
+ // upstream afterwards cannot work: `--set-upstream-to` needs a
713
+ // remote-tracking ref, and a URL push writes none.
714
+ const adopt = !git(["remote", "get-url", "origin"]);
715
+ if (adopt) git(["remote", "add", "origin", url]);
716
+ // An author who already has an `origin` keeps it, and the push goes to the
717
+ // URL directly rather than quietly redirecting their remote.
718
+ const pushed = adopt
719
+ ? git(["push", "-u", "origin", `${branch}:${branch}`], env)
720
+ : git(["push", url, `${branch}:${branch}`], env);
721
+ if (pushed === null) {
722
+ // Leave nothing behind that was not there before.
723
+ if (adopt) git(["remote", "remove", "origin"]);
724
+ return false;
725
+ }
726
+ return true;
727
+ } finally {
728
+ try {
729
+ rmSync(dirname(askpass), { recursive: true, force: true });
730
+ } catch {
731
+ /* a leftover temp dir is not worth failing a publish over */
732
+ }
733
+ }
734
+ }
735
+
736
+ /**
737
+ * The minimum that gives a repository a default branch: one commit, made
738
+ * through the API. Only for a pack published from somewhere that is not a git
739
+ * checkout — otherwise the author's own history does this job better.
740
+ */
741
+ async function seedDefaultBranch(owner: string, name: string, id: string, token: string): Promise<void> {
742
+ await gh(`${GITHUB_API}/repos/${owner}/${name}/contents/README.md`, token, {
743
+ method: "PUT",
744
+ contentType: "application/json",
745
+ body: JSON.stringify({
746
+ message: `${id}: create pack repository`,
747
+ content: Buffer.from(
748
+ `# ${name}\n\nA [failproofai](https://github.com/failproofai/failproofai) policy pack.\n\n\`\`\`bash\nfailproofai policies add ${owner}/${name}\n\`\`\`\n`,
749
+ "utf8",
750
+ ).toString("base64"),
751
+ }),
752
+ });
753
+ }
754
+
628
755
  /**
629
756
  * Where `bun` is, if it is anywhere.
630
757
  *
@@ -736,6 +863,9 @@ function publishEntryArg(rest: string[]): string | undefined {
736
863
 
737
864
  const GITHUB_API = process.env.FAILPROOFAI_GITHUB_API ?? "https://api.github.com";
738
865
  const GITHUB_UPLOADS = process.env.FAILPROOFAI_GITHUB_UPLOADS ?? "https://uploads.github.com";
866
+ /** Where the git remote lives, so the push path can be tested against a real
867
+ * local bare repository rather than only reasoned about. */
868
+ const GITHUB_GIT = process.env.FAILPROOFAI_GITHUB_GIT ?? "https://github.com";
739
869
 
740
870
  /**
741
871
  * The credential, from the places a developer already keeps one.
@@ -822,6 +952,60 @@ function ghError(res: { status: number; json: Record<string, unknown> | null; te
822
952
  * - a private repository, which publishes to nobody, because installs are
823
953
  * anonymous HTTPS with no credential to offer.
824
954
  */
955
+ /**
956
+ * The two things `publish` cannot work out on its own, asked instead of
957
+ * demanded as flags.
958
+ *
959
+ * Everything else it already derives: the policy files by content, the version
960
+ * by counting the repository's own releases, the id from the repository, the
961
+ * credential from the environment. What is left is genuinely a question —
962
+ * WHERE this should live, when the folder has no git remote naming somewhere —
963
+ * and a confirmation, because publishing is public and a version number can
964
+ * never be reused.
965
+ *
966
+ * Only ever on a TTY. A pipe, a CI job or a test gets the old behaviour: flags
967
+ * decide, and a missing `--repo` still means "build the assets and stop"
968
+ * rather than a prompt nobody can answer.
969
+ */
970
+ async function askWhereToPublish(
971
+ suggestion: string,
972
+ io: { stdin: TTYIn; stdout: TTYOut },
973
+ ): Promise<string | null> {
974
+ const answer = await promptText({
975
+ // The suggestion goes in the HINT, not just in `defaultValue`: the hint is
976
+ // what renders as the placeholder, while `defaultValue` is only applied on
977
+ // an empty submit and is never shown. Passing it as the default alone left
978
+ // the one keystroke that finishes this prompt — return — invisible.
979
+ message: "Where should this publish?",
980
+ hint: `${suggestion} · created if it does not exist`,
981
+ defaultValue: suggestion,
982
+ validate: (v) => {
983
+ const t = v.trim();
984
+ if (!/^[A-Za-z0-9][\w.-]*\/[A-Za-z0-9][\w.-]*$/.test(t)) return "owner/repo";
985
+ return null;
986
+ },
987
+ stdin: io.stdin,
988
+ stdout: io.stdout,
989
+ });
990
+ return answer === null ? null : answer.trim();
991
+ }
992
+
993
+ /**
994
+ * The account the credential belongs to, for the default answer above.
995
+ *
996
+ * Best-effort: a failure here costs a nicer default and nothing else, so it
997
+ * never blocks or reports. The prompt still has the folder name to fall back
998
+ * on, which is what the repository would most likely be called anyway.
999
+ */
1000
+ async function credentialLogin(token: string): Promise<string | null> {
1001
+ try {
1002
+ const me = await gh(`${GITHUB_API}/user`, token);
1003
+ return typeof me.json?.login === "string" ? me.json.login : null;
1004
+ } catch {
1005
+ return null;
1006
+ }
1007
+ }
1008
+
825
1009
  async function publish(rest: string[]): Promise<PackCliResult> {
826
1010
  const flag = (name: string): string | undefined => {
827
1011
  const i = rest.findIndex((a) => a === `--${name}` || a.startsWith(`--${name}=`));
@@ -838,7 +1022,32 @@ async function publish(rest: string[]): Promise<PackCliResult> {
838
1022
  // it is that file and only that file.
839
1023
  const discovered = entry ? [] : findEntry(process.cwd());
840
1024
  if (!entry && discovered.length > 0) entry = discovered[0];
841
- const repo = flag("repo") ?? (entry ? inferRepo(entry) : null) ?? undefined;
1025
+ let repo = flag("repo") ?? (entry ? inferRepo(entry) : null) ?? undefined;
1026
+ // Nothing names a destination and there is somebody to ask. This is the
1027
+ // whole of "just run `failproofai publish`": the folder is a git repo full
1028
+ // of policies, and the one thing it cannot know is where they should go.
1029
+ const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
1030
+ const askingWhere = interactive && !repo && entry && !rest.includes("--dry-run");
1031
+ if (askingWhere) {
1032
+ // What is about to be published, before being asked where to put it. The
1033
+ // question is answerable without it — but "publish" with no arguments
1034
+ // otherwise gives no sign of WHICH files it found, and finding the wrong
1035
+ // ones is the mistake that matters here.
1036
+ const found = discovered.length > 0 ? discovered : [entry!];
1037
+ process.stdout.write(
1038
+ `\n ${found.length} policy ${found.length === 1 ? "file" : "files"}: ` +
1039
+ `${found.map((f) => basename(f)).join(", ")}\n\n`,
1040
+ );
1041
+ const token = githubToken();
1042
+ const login = token ? await credentialLogin(token) : null;
1043
+ const folder = basename(resolve(entry!, ".."));
1044
+ const answered = await askWhereToPublish(
1045
+ `${login ?? "your-account"}/${folder}`,
1046
+ { stdin: process.stdin as unknown as TTYIn, stdout: process.stdout as unknown as TTYOut },
1047
+ );
1048
+ if (answered === null) return ok(["Nothing was published."]);
1049
+ repo = answered;
1050
+ }
842
1051
  // A tag on HEAD is somebody SAYING what this release is, so it wins over a
843
1052
  // counted one. Everything else is decided after the repository is known,
844
1053
  // because the count comes from what that repository has already published.
@@ -846,8 +1055,19 @@ async function publish(rest: string[]): Promise<PackCliResult> {
846
1055
  let versionCounted = false;
847
1056
  // The id and the repo are usually the same words, and requiring both is asking
848
1057
  // the same question twice. Either one alone answers for the other.
849
- const id = flag("id") ?? repo;
850
1058
  const dryRun = rest.includes("--dry-run") || !repo;
1059
+ // A dry run publishes nothing, so the id only has to name the artifact it
1060
+ // writes — and refusing to build one because the folder has no git remote
1061
+ // yet blocked the exact thing a dry run is for: looking at the pack BEFORE
1062
+ // committing to a repository for it. The folder name is what the repository
1063
+ // would be called anyway, and `--id` or `--repo` overrides it the moment
1064
+ // either is known.
1065
+ //
1066
+ // `local/` rather than a guessed account: the owner is genuinely not known
1067
+ // yet, and a plausible-looking one would be baked into a manifest somebody
1068
+ // could upload by hand.
1069
+ const id =
1070
+ flag("id") ?? repo ?? (dryRun && entry ? `local/${basename(resolve(entry, ".."))}` : undefined);
851
1071
  const [owner, name] = (repo ?? "/").split("/");
852
1072
  if (repo && (!owner || !name || repo.split("/").length !== 2)) {
853
1073
  return fail([`--repo must be <owner>/<repo>, got ${JSON.stringify(repo)}`]);
@@ -899,7 +1119,7 @@ async function publish(rest: string[]): Promise<PackCliResult> {
899
1119
  "It needs write access to releases on that repository, and nothing else.",
900
1120
  ]);
901
1121
  }
902
- const ensured = await ensureRepo(owner, name, id, token);
1122
+ const ensured = await ensureRepo(owner, name, id, token, resolve(entry, ".."));
903
1123
  if ("error" in ensured) return fail(ensured.error);
904
1124
  created = ensured.created;
905
1125
  repoInfo = ensured.info;
@@ -953,7 +1173,13 @@ async function publish(rest: string[]): Promise<PackCliResult> {
953
1173
  ? ["Dry run — nothing was published.", `Drop --dry-run to release it on ${repo}.`]
954
1174
  : [
955
1175
  "Nothing was published: name a repository to release it on.",
956
- ` failproofai publish ${entry} --repo <owner>/<repo> --version ${version}`,
1176
+ // Just the repository. It used to spell out the entry file and the
1177
+ // version too — naming ONE of the files it had that moment finished
1178
+ // bundling, and pinning a version it works out by counting the
1179
+ // repository's own releases. Both were wrong the moment they were
1180
+ // printed, and both taught the reader that publishing needs flags
1181
+ // it does not need.
1182
+ " failproofai publish --repo <owner>/<repo>",
957
1183
  ]),
958
1184
  ]);
959
1185
  }
@@ -1,3 +0,0 @@
1
- module.exports=[22734,(e,r,t)=>{r.exports=e.x("fs",()=>require("fs"))},24868,(e,r,t)=>{r.exports=e.x("fs/promises",()=>require("fs/promises"))},70406,(e,r,t)=>{r.exports=e.x("next/dist/compiled/@opentelemetry/api",()=>require("next/dist/compiled/@opentelemetry/api"))},18622,(e,r,t)=>{r.exports=e.x("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js",()=>require("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js"))},20635,(e,r,t)=>{r.exports=e.x("next/dist/server/app-render/action-async-storage.external.js",()=>require("next/dist/server/app-render/action-async-storage.external.js"))},24725,(e,r,t)=>{r.exports=e.x("next/dist/server/app-render/after-task-async-storage.external.js",()=>require("next/dist/server/app-render/after-task-async-storage.external.js"))},56704,(e,r,t)=>{r.exports=e.x("next/dist/server/app-render/work-async-storage.external.js",()=>require("next/dist/server/app-render/work-async-storage.external.js"))},32319,(e,r,t)=>{r.exports=e.x("next/dist/server/app-render/work-unit-async-storage.external.js",()=>require("next/dist/server/app-render/work-unit-async-storage.external.js"))},59043,(e,r,t)=>{r.exports=e.x("next/dist/server/runtime-reacts.external.js",()=>require("next/dist/server/runtime-reacts.external.js"))},93695,(e,r,t)=>{r.exports=e.x("next/dist/shared/lib/no-fallback-error.external.js",()=>require("next/dist/shared/lib/no-fallback-error.external.js"))},12714,(e,r,t)=>{r.exports=e.x("node:fs/promises",()=>require("node:fs/promises"))},50227,(e,r,t)=>{r.exports=e.x("node:path",()=>require("node:path"))},81111,(e,r,t)=>{r.exports=e.x("node:stream",()=>require("node:stream"))},46786,(e,r,t)=>{r.exports=e.x("os",()=>require("os"))},14747,(e,r,t)=>{r.exports=e.x("path",()=>require("path"))},91301,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__1qb590j._.js","server/chunks/_1vslkoe._.js"].map(r=>e.l(r))).then(()=>r(30441)))},16341,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__1shcqgr._.js"].map(r=>e.l(r))).then(()=>r(93114)))},37352,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__1jm9fw6._.js"].map(r=>e.l(r))).then(()=>r(36203)))},18944,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__17g9wh7._.js","server/chunks/src_hooks_fp-home_ts_09kv0bn._.js"].map(r=>e.l(r))).then(()=>r(57232)))},71809,e=>{"use strict";async function r(e,r){let t=Array(e.length),s=0;async function o(){for(;s<e.length;){let r=s++;try{t[r]={status:"fulfilled",value:await e[r]()}}catch(e){t[r]={status:"rejected",reason:e}}}}let a=Array.from({length:Math.min(r,e.length)},()=>o());return await Promise.all(a),t}e.s(["batchAll",0,r])},5807,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__1w9zl9-._.js"].map(r=>e.l(r))).then(()=>r(55851)))},21476,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__1legmza._.js"].map(r=>e.l(r))).then(()=>r(78166)))},97452,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__1ou2ehh._.js"].map(r=>e.l(r))).then(()=>r(46413)))},23414,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__0rv7m0k._.js"].map(r=>e.l(r))).then(()=>r(72094)))},52400,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__0g6bbuw._.js","server/chunks/_1vslkoe._.js"].map(r=>e.l(r))).then(()=>r(79364)))},53229,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__1ffkmds._.js","server/chunks/_1vslkoe._.js"].map(r=>e.l(r))).then(()=>r(40375)))},62998,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__0q0qzx1._.js"].map(r=>e.l(r))).then(()=>r(69391)))},95231,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__0--lkk6._.js"].map(r=>e.l(r))).then(()=>r(28246)))},28557,e=>{"use strict";e.s(["formatDate",0,function(e){return new Intl.DateTimeFormat("en-US",{month:"short",day:"numeric",year:"numeric",hour:"numeric",minute:"2-digit",hour12:!0}).format(e)}])},31854,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__08w4wmd._.js","server/chunks/_1vslkoe._.js"].map(r=>e.l(r))).then(()=>r(69164)))},49081,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__1xuedea._.js","server/chunks/_1vslkoe._.js"].map(r=>e.l(r))).then(()=>r(36618)))},67347,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__06cuf1y._.js","server/chunks/_1vslkoe._.js"].map(r=>e.l(r))).then(()=>r(64828)))},32359,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__0jnjf2t._.js","server/chunks/_1vslkoe._.js"].map(r=>e.l(r))).then(()=>r(3605)))},40911,e=>{"use strict";let r={info:0,warn:1,error:2};function t(e){return r[e]>=r.warn}function s(e){return`[failproofai${new Date().toISOString()}] ${e}`}e.s(["logActivity",0,function(e,r,o){if(!t("info"))return;let a=[`user=${e}`,`action=${r}`];o&&a.push(o),console.log(s("ACTIVITY"),a.join(" "))},"logError",0,function(e,r){void 0!==r?console.error(s("ERROR"),e,r):console.error(s("ERROR"),e)},"logWarn",0,function(e,r){t("warn")&&(void 0!==r?console.warn(s("WARN"),e,r):console.warn(s("WARN"),e))}])},38978,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__04_h-a5._.js"].map(r=>e.l(r))).then(()=>r(90624)))},26435,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__0-219ec._.js"].map(r=>e.l(r))).then(()=>r(64199)))},82978,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__1mhmdzs._.js"].map(r=>e.l(r))).then(()=>r(35435)))},82859,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__1qxztj-._.js"].map(r=>e.l(r))).then(()=>r(99440)))},81580,e=>{"use strict";var r=e.i(46786),t=e.i(14747);e.s(["decodeFolderName",0,function(e){return/^[A-Za-z]--/.test(e)?e[0]+":/"+e.slice(3).replace(/-/g,"/"):e.replace(/-/g,"/")},"encodeFolderName",0,function(e){let r=/^([A-Za-z]):[\\/](.*)$/.exec(e);return r?r[1]+"--"+r[2].replace(/[\\/]/g,"-"):e.replace(/[\\/]/g,"-")},"getClaudeProjectsPath",0,function(){let e=process.env.CLAUDE_PROJECTS_PATH;return e||(0,t.join)((0,r.homedir)(),".claude","projects")}])},45093,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__0f7mikp._.js"].map(r=>e.l(r))).then(()=>r(19791)))},41330,e=>{e.v(r=>Promise.all(["server/chunks/[root-of-the-server]__0q-v9z2._.js"].map(r=>e.l(r))).then(()=>r(85116)))},56936,e=>{"use strict";var r=e.i(12714),t=e.i(50227),s=e.i(81580),o=e.i(83534),a=e.i(71809),n=e.i(40911),i=e.i(28557);let l=/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/;async function c(e,t){try{return(await (0,r.stat)(e)).mtime}catch(e){return(0,n.logWarn)(`Failed to stat ${t}:`,e),new Date(0)}}async function u(e){try{if(!(await (0,r.stat)(e)).isDirectory())return null;return await (0,r.readdir)(e,{withFileTypes:!0})}catch{return null}}async function h(){try{let e=(0,s.getClaudeProjectsPath)(),r=await u(e);if(!r)return[];let o=(await (0,a.batchAll)(r.filter(e=>e.isDirectory()).map(r=>async()=>{let s=(0,t.join)(e,r.name),o=await c(s,r.name);return{name:r.name,path:s,isDirectory:!0,lastModified:o,lastModifiedFormatted:(0,i.formatDate)(o),cli:["claude"]}}),16)).filter(e=>"fulfilled"===e.status).map(e=>e.value);return o.sort((e,r)=>r.lastModified.getTime()-e.lastModified.getTime()),o}catch(e){return(0,n.logError)("Error reading Claude project folders:",e),[]}}async function d(){let[{getCodexProjects:r},{getCopilotProjects:t},{getCursorProjects:s},{getOpenCodeProjects:o},{getPiProjects:a},{getHermesProjects:i},{getOpenClawProjects:l},{getFactoryProjects:c},{getDevinProjects:u},{getAntigravityProjects:d},{getGooseProjects:m}]=await Promise.all([e.A(37352),e.A(5807),e.A(97452),e.A(82978),e.A(45093),e.A(67347),e.A(38978),e.A(62998),e.A(52400),e.A(91301),e.A(31854)]),[f,p,v,_,j,g,x,k,w,y,P,E]=await Promise.all([h(),r().catch(e=>((0,n.logError)("Error reading Codex projects:",e),[])),t().catch(e=>((0,n.logError)("Error reading Copilot projects:",e),[])),s().catch(e=>((0,n.logError)("Error reading Cursor projects:",e),[])),o().catch(e=>((0,n.logError)("Error reading OpenCode projects:",e),[])),a().catch(e=>((0,n.logError)("Error reading Pi projects:",e),[])),i().catch(e=>((0,n.logError)("Error reading Hermes projects:",e),[])),l().catch(e=>((0,n.logError)("Error reading OpenClaw projects:",e),[])),c().catch(e=>((0,n.logError)("Error reading Factory projects:",e),[])),u().catch(e=>((0,n.logError)("Error reading Devin projects:",e),[])),d().catch(e=>((0,n.logError)("Error reading Antigravity projects:",e),[])),m().catch(e=>((0,n.logError)("Error reading Goose projects:",e),[]))]);return function(...e){let r=new Map;for(let t of e)for(let e of t){let t=r.get(e.name);if(!t){r.set(e.name,{...e,cli:[...e.cli]});continue}let s=[...t.cli];for(let r of e.cli)s.includes(r)||s.push(r);let o=e.lastModified.getTime()>t.lastModified.getTime()?e:t;r.set(e.name,{...t,cli:s,lastModified:o.lastModified,lastModifiedFormatted:o.lastModifiedFormatted,sessionCount:void 0===t.sessionCount&&void 0===e.sessionCount?void 0:(t.sessionCount??0)+(e.sessionCount??0)})}let t=Array.from(r.values());return t.sort((e,r)=>r.lastModified.getTime()-e.lastModified.getTime()),t}(f,p,v,_,j,g,x,k,w,y,P,E)}function m(e){if(!e)throw RangeError("Empty project name");if(/^[/\\]/.test(e))throw RangeError("Absolute project name");let r=(0,t.resolve)((0,s.getClaudeProjectsPath)()),o=(0,t.resolve)((0,t.join)(r,e));if(!o.startsWith(r+t.sep))throw RangeError("Project path escapes root");return o}function f(e){let r=e.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i);return r?r[0]:void 0}async function p(e){try{let r=await u(e);if(!r)return[];let s=r.filter(e=>e.isFile()&&e.name.endsWith(".jsonl")&&f(e.name)),o=(await (0,a.batchAll)(s.map(r=>async()=>{let s=(0,t.join)(e,r.name),o=await c(s,r.name);return{name:r.name,path:s,lastModified:o,lastModifiedFormatted:(0,i.formatDate)(o),sessionId:f(r.name),cli:"claude"}}),16)).filter(e=>"fulfilled"===e.status).map(e=>e.value);return o.sort((e,r)=>r.lastModified.getTime()-e.lastModified.getTime()),o}catch(e){return(0,n.logError)("Error reading session files:",e),[]}}(0,o.runtimeCache)(d,30),(0,o.runtimeCache)(e=>p(e),30),e.s(["UUID_RE",0,l,"resolveProjectPath",0,m,"resolveSessionFilePath",0,function(e,r){if(!l.test(r))throw RangeError("Invalid session ID");let s=m(e);return(0,t.join)(s,`${r}.jsonl`)}])},83534,e=>{"use strict";e.s(["runtimeCache",0,function(e,r,t){let s=new Map,o=new Map,a=t?.maxSize;return async(...t)=>{let n=JSON.stringify(t),i=s.get(n);if(i&&Date.now()<i.expiry)return i.data;let l=o.get(n);if(l)return l;let c=e(...t).then(e=>{if(o.delete(n),a&&s.size>=a){let e=s.keys().next().value;s.delete(e)}return s.set(n,{data:e,expiry:Date.now()+1e3*r}),e},e=>{throw o.delete(n),e});return o.set(n,c),c}}])}];
2
-
3
- //# sourceMappingURL=%5Broot-of-the-server%5D__1l-khtb._.js.map
@@ -1,3 +0,0 @@
1
- module.exports=[74533,(e,t,r)=>{t.exports=e.x("node:child_process",()=>require("node:child_process"))},35435,e=>{"use strict";var t=e.i(74533),r=e.i(81580),o=e.i(83534),i=e.i(28557),d=e.i(40911);function n(e){try{let r=(0,t.execFileSync)("opencode",["db","--format","json",e],{encoding:"utf8",timeout:5e3,stdio:["ignore","pipe","pipe"]});if(!r.trim())return[];let o=JSON.parse(r);if(!Array.isArray(o))return null;return o}catch{return null}}function s(){return n("SELECT id, project_id, slug, directory, title, time_created, time_updated FROM session ORDER BY time_updated DESC LIMIT 1000")}function a(){return n("SELECT id, worktree, vcs, name, time_created, time_updated FROM project")}async function l(){let e=s(),t=a();if(null===e&&null===t)return[];let o=new Map;for(let e of t??[])o.set(e.id,e);let d=new Map;for(let t of e??[]){if(!t.project_id)continue;let e=d.get(t.project_id);e||(e={rows:[],latest:0},d.set(t.project_id,e)),e.rows.push(t),t.time_updated>e.latest&&(e.latest=t.time_updated)}let n=new Set,l=[];for(let[e,t]of d){n.add(e);let d=o.get(e),s=d?.worktree??t.rows[0]?.directory??null,a=s?(0,r.encodeFolderName)(s):e,c=s??"",u=new Date(Math.max(t.latest,d?.time_updated??0));l.push({name:a,path:c,isDirectory:!0,lastModified:u,lastModifiedFormatted:(0,i.formatDate)(u),cli:["opencode"]})}for(let e of t??[]){if(n.has(e.id))continue;let t=e.worktree??"",o=t?(0,r.encodeFolderName)(t):e.id,d=new Date(e.time_updated);l.push({name:o,path:t,isDirectory:!0,lastModified:d,lastModifiedFormatted:(0,i.formatDate)(d),cli:["opencode"]})}return l.sort((e,t)=>t.lastModified.getTime()-e.lastModified.getTime()),l}async function c(e){let t=s();return t?t.filter(t=>t.directory===e).map(e=>{let t=new Date(e.time_updated);return{name:e.title??e.slug??e.id,path:`opencode://${e.id}`,lastModified:t,lastModifiedFormatted:(0,i.formatDate)(t),sessionId:e.id,cli:"opencode"}}):[]}async function u(e){let t,o;try{t=a(),o=s()}catch(e){return(0,d.logWarn)("Failed to read OpenCode DB:",e),{cwd:null,sessions:[]}}if(!t||!o)return{cwd:null,sessions:[]};let n=t.find(t=>t.worktree&&(0,r.encodeFolderName)(t.worktree)===e);if(!n||!n.worktree)return{cwd:null,sessions:[]};let l=o.filter(e=>e.project_id===n.id);return{cwd:n.worktree,sessions:l.map(e=>{let t=new Date(e.time_updated);return{name:e.title??e.slug??e.id,path:`opencode://${e.id}`,lastModified:t,lastModifiedFormatted:(0,i.formatDate)(t),sessionId:e.id,cli:"opencode"}})}}let p=(0,o.runtimeCache)(l,30),m=(0,o.runtimeCache)(e=>c(e),30,{maxSize:50}),f=(0,o.runtimeCache)(e=>u(e),30,{maxSize:50});e.s(["getCachedOpenCodeProjects",0,p,"getCachedOpenCodeSessionsByEncodedName",0,f,"getCachedOpenCodeSessionsForCwd",0,m,"getOpenCodeProjects",0,l,"getOpenCodeSessionsByEncodedName",0,u,"getOpenCodeSessionsForCwd",0,c])}];
2
-
3
- //# sourceMappingURL=%5Broot-of-the-server%5D__1mhmdzs._.js.map
@@ -1,3 +0,0 @@
1
- module.exports=[74533,(t,e,i)=>{e.exports=t.x("node:child_process",()=>require("node:child_process"))},54214,67405,t=>{"use strict";var e=t.i(24868),i=t.i(14747),n=t.i(81580),s=t.i(56936);async function r(t,n,s,r){let a=`agent-${r}.jsonl`;for(let r of[(0,i.join)(t,n,a),(0,i.join)(t,n,s,a),(0,i.join)(t,n,s,"subagents",a)])if(!(0,i.relative)(t,r).startsWith(".."))try{return await (0,e.access)(r),r}catch(t){if("ENOENT"===t.code)continue;break}return null}var a=t.i(83534),o=t.i(71809),u=t.i(28557);function l(t){if(t<1e3)return`${t}ms`;let e=Math.round(t/100);if(e<600)return`${(e/10).toFixed(1)}s`;let i=Math.round(t/1e3);if(i<3600){let t=Math.floor(i/60);return`${t}m ${i%60}s`}let n=Math.round(t/6e4),s=Math.floor(n/60);return`${s}h ${n%60}m`}function d(t){let e=(0,u.formatDate)(t),i=t.getMilliseconds().toString().padStart(3,"0");return`${e}.${i}`}function m(t,e,i,n){return{_source:n,uuid:t.uuid||"",parentUuid:t.parentUuid??null,timestamp:e,timestampMs:i.getTime(),timestampFormatted:d(i)}}async function p(t,e){let i=t.split("\n").filter(t=>""!==t.trim()),n=new Map,s=[],r=[],a=new Set,o=!1;for(let t=0;t<i.length;t++){let u;t>0&&t%200==0&&await new Promise(t=>setImmediate(t));let l=i[t];try{u=JSON.parse(l)}catch{continue}let d={...u,_source:e};r.push(d);let p=u.type,c=u.timestamp;if(!c)continue;let f=new Date(c),g=f.getTime();if("user"===p){let t=u.message;if(Array.isArray(t?.content)){let e=t.content;if(e.some(t=>"tool_result"===t.type)){let t=u.toolUseResult,i="string"==typeof t?.agentId?t.agentId:void 0;for(let t of(i&&/^[a-f0-9]+$/.test(i)&&a.add(i),e)){if("tool_result"!==t.type)continue;let e=t.tool_use_id;if(!e)continue;let{text:s,images:r}=function(t){let e=t.content;if("string"==typeof e)return{text:e};if(Array.isArray(e)){let t=e.filter(t=>"text"===t.type).map(t=>t.text),i=e.filter(t=>"image"===t.type).map(t=>{let e=t.source;return{base64:e.data,mediaType:e.media_type}}).filter(t=>t.base64&&t.mediaType);return{text:t.length>0?t.join("\n"):void 0,images:i.length>0?i:void 0}}return{}}(t);n.set(e,{timestamp:c,timestampMs:g,content:s,images:r,agentId:i})}continue}}let i="string"==typeof t?.content?t.content:"";s.push({type:"user",...m(u,c,f,e),message:{role:"user",content:i}});continue}if("assistant"===p){let t=u.message,i=[];if(Array.isArray(t?.content)&&(i=t.content.filter(t=>["text","tool_use","thinking"].includes(t.type)).map(t=>{if("text"===t.type)return{type:"text",text:t.text};if("tool_use"===t.type){let e=t.input;return{type:"tool_use",id:t.id,name:t.name,input:t.input??{},..."Task"===t.name&&e?{subagentType:e.subagent_type,subagentDescription:e.description}:{}}}return{type:"thinking",thinking:t.thinking,signature:t.signature}})),0===i.length)continue;s.push({type:"assistant",...m(u,c,f,e),message:{role:"assistant",content:i,model:t?.model}});continue}if("file-history-snapshot"===p||"progress"===p||"system"===p){s.push({type:p,...m(u,c,f,e),raw:{...u}});continue}if("queue-operation"===p){let t=o?"Session Resumed":"Session Started";o=!0,s.push({type:"queue-operation",...m(u,c,f,e),label:t});continue}}let u=0;for(let t of s)if("assistant"===t.type)for(let e of(++u%200==0&&await new Promise(t=>setImmediate(t)),t.message.content)){if("tool_use"!==e.type)continue;let i=n.get(e.id);if(!i)continue;let s=new Date(i.timestamp),r=Math.max(0,i.timestampMs-t.timestampMs);e.result={timestamp:i.timestamp,timestampFormatted:d(s),content:i.content,images:i.images,durationMs:r,durationFormatted:l(r)},i.agentId&&(e.subagentId=i.agentId)}return s.length>500&&await new Promise(t=>setImmediate(t)),s.sort((t,e)=>t.timestampMs-e.timestampMs),{entries:s,rawLines:r,subagentIds:Array.from(a)}}async function c(t,e="session"){return(await p(t,e)).entries}async function f(t,a){let u=(0,s.resolveProjectPath)(t),l=(0,n.getClaudeProjectsPath)(),d=(0,i.join)(u,`${a}.jsonl`),m=await (0,e.readFile)(d,"utf-8"),{entries:c,rawLines:f,subagentIds:g}=await p(m,"session");if(0===g.length)return{entries:c,rawLines:f,subagentIds:[]};let y=await (0,o.batchAll)(g.map(i=>async()=>{let n=`agent-${i}`,s=await r(l,t,a,i);if(!s)return null;let o=await (0,e.readFile)(s,"utf-8"),{entries:u,rawLines:d}=await p(o,n);return{entries:u,rawLines:d}}),4),_=[...c],h=[...f];for(let t of y)"fulfilled"===t.status&&t.value&&(_.push(...t.value.entries),h.push(...t.value.rawLines));return _.length>500&&await new Promise(t=>setImmediate(t)),_.sort((t,e)=>t.timestampMs-e.timestampMs),{entries:_,rawLines:h,subagentIds:g}}t.s(["formatDuration",0,l],67405),(0,a.runtimeCache)((t,e)=>f(t,e),60,{maxSize:50}),t.s(["baseEntry",0,m,"formatTimestamp",0,d,"parseLogContent",0,c,"parseRawLines",0,function(t,e){return t.split("\n").filter(t=>""!==t.trim()).flatMap(t=>{try{let i=JSON.parse(t);return void 0!==e&&(i._source=e),[i]}catch{return[]}})}],54214)},99440,t=>{"use strict";var e=t.i(74533),i=t.i(83534),n=t.i(54214),s=t.i(67405);function r(t){try{let i=(0,e.execFileSync)("opencode",["db","--format","json",t],{encoding:"utf8",timeout:5e3,stdio:["ignore","pipe","pipe"]});if(!i.trim())return[];let n=JSON.parse(i);if(!Array.isArray(n))return null;return n}catch{return null}}function a(t){return!!t&&"object"==typeof t&&!Array.isArray(t)}function o(t){if("string"!=typeof t||0===t.length)return null;try{let e=JSON.parse(t);return a(e)?e:null}catch{return null}}async function u(t){if(!t||!/^[A-Za-z0-9_-]+$/.test(t))return null;let e=r(`SELECT id, project_id, slug, directory, title, time_created, time_updated FROM session WHERE id = '${t}'`);if(!e||0===e.length)return null;let i=e[0],u=r(`SELECT id, session_id, time_created, time_updated, data FROM message WHERE session_id = '${t}' ORDER BY time_created ASC`),l=r(`SELECT id, message_id, session_id, time_created, time_updated, data FROM part WHERE session_id = '${t}' ORDER BY time_created ASC`);if(!u)return{entries:[],rawLines:[],cwd:i.directory??void 0,filePath:`opencode://${t}`};let d=new Map;for(let t of l??[]){let e=d.get(t.message_id);e||(e=[],d.set(t.message_id,e)),e.push(t)}let m=[],p=[];for(let t of u){let e=d.get(t.id)??[];m.push(function(t,e,i){let r=o(t.data)??{},u="string"==typeof r.role?r.role:"system",l=new Date(t.time_created),d=l.toISOString(),m={uuid:t.id,parentUuid:null},p=(0,n.baseEntry)(m,d,l,i),c=[],f="";for(let t of e){let e=o(t.data);if(!e)continue;let i="string"==typeof e.type?e.type:"unknown";if("text"===i){let t="string"==typeof e.text?e.text:"string"==typeof e.content?e.content:"";t&&(c.push({type:"text",text:t}),f+=(f?"\n":"")+t);continue}if("tool"===i){let i="string"==typeof e.tool?e.tool:"string"==typeof e.name?e.name:"tool",r=a(e.state)?e.state:null,o=r&&a(r.input)?r.input:a(e.input)?e.input:a(e.args)?e.args:{},u={type:"tool_use",id:t.id,name:i,input:o},l=r&&"string"==typeof r.status?r.status:"";if(r&&("completed"===l||"error"===l)){let e=("error"===l&&"string"==typeof r.error?r.error:null)??r.output,i="string"==typeof e?e:null!=e?JSON.stringify(e):"",o=a(r.time)?r.time:{},d="number"==typeof o.start?o.start:t.time_created,m="number"==typeof o.end?o.end:t.time_updated,p=Math.max(0,m-d),c=new Date(m);u.result={timestamp:c.toISOString(),timestampFormatted:(0,n.formatTimestamp)(c),content:i,durationMs:p,durationFormatted:(0,s.formatDuration)(p)}}c.push(u);continue}c.push({type:"text",text:`[opencode ${i}]`})}if("user"===u)return{...p,type:"user",message:{role:"user",content:f}};if("assistant"===u){let t=a(r.model)?r.model:null,e=t&&"string"==typeof t.modelID?t.modelID:void 0;return{...p,type:"assistant",message:{role:"assistant",content:c,model:e}}}return{...p,type:"system",raw:{id:t.id,role:u,parts:c}}}(t,e,"session"));let i=o(t.data);p.push({id:t.id,session_id:t.session_id,time_created:t.time_created,data:i??t.data})}return{entries:m,rawLines:p,cwd:i.directory??void 0,filePath:`opencode://${t}`}}async function l(t){if(!t||!/^[A-Za-z0-9_-]+$/.test(t))return null;let e=r(`SELECT id, project_id, slug, directory, title, time_created, time_updated FROM session WHERE id = '${t}'`);if(!e||0===e.length)return null;let i=r(`SELECT id, session_id, time_created, time_updated, data FROM message WHERE session_id = '${t}' ORDER BY time_created ASC`),n=r(`SELECT id, message_id, session_id, time_created, time_updated, data FROM part WHERE session_id = '${t}' ORDER BY time_created ASC`);return null===i||null===n?null:{session:e[0],messages:i.map(t=>({...t,data:o(t.data)??t.data})),parts:n.map(t=>({...t,data:o(t.data)??t.data}))}}(0,i.runtimeCache)(t=>u(t),30,{maxSize:50}),t.s(["getOpenCodeSessionExport",0,l,"getOpenCodeSessionLog",0,u])}];
2
-
3
- //# sourceMappingURL=%5Broot-of-the-server%5D__1qxztj-._.js.map