pushary 1.9.31 → 1.9.34

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 (105) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/data/SKILL.md +6 -7
  3. package/data/cowork/SKILL.md +2 -2
  4. package/data/cursor-plugin/rules/pushary.mdc +1 -1
  5. package/data/cursor-plugin/skills/pushary/SKILL.md +6 -7
  6. package/data/vscode-plugin/skills/pushary/SKILL.md +6 -7
  7. package/dist/bin/pushary-bell-hook.js +25 -25
  8. package/dist/bin/pushary-bell.js +9 -9
  9. package/dist/bin/pushary-claude.js +24 -24
  10. package/dist/bin/pushary-clean.js +29 -29
  11. package/dist/bin/pushary-codex-bridge.js +17 -17
  12. package/dist/bin/pushary-codex-hook.js +30 -30
  13. package/dist/bin/pushary-codex.js +12 -12
  14. package/dist/bin/pushary-connect.js +24 -24
  15. package/dist/bin/pushary-cowork.js +5 -5
  16. package/dist/bin/pushary-daemon.js +32 -32
  17. package/dist/bin/pushary-disconnect.js +24 -24
  18. package/dist/bin/pushary-doctor.js +33 -33
  19. package/dist/bin/pushary-elicitation-hook.js +25 -25
  20. package/dist/bin/pushary-gemini-bridge.js +13 -13
  21. package/dist/bin/pushary-gemini-hook.js +27 -27
  22. package/dist/bin/pushary-hook.js +29 -29
  23. package/dist/bin/pushary-login.js +12 -12
  24. package/dist/bin/pushary-logout.js +24 -24
  25. package/dist/bin/pushary-mcp.js +9 -9
  26. package/dist/bin/pushary-mode.js +12 -12
  27. package/dist/bin/pushary-notification-hook.js +24 -24
  28. package/dist/bin/pushary-opencode-hook.js +26 -26
  29. package/dist/bin/pushary-permission-denied-hook.js +29 -29
  30. package/dist/bin/pushary-permission-hook.js +28 -28
  31. package/dist/bin/pushary-post-hook.js +24 -24
  32. package/dist/bin/pushary-prompt-hook.js +24 -24
  33. package/dist/bin/pushary-session-end-hook.js +24 -24
  34. package/dist/bin/pushary-session-start-hook.js +28 -28
  35. package/dist/bin/pushary-setup.js +35 -35
  36. package/dist/bin/pushary-stats.js +5 -5
  37. package/dist/bin/pushary-status.js +26 -26
  38. package/dist/bin/pushary-stop-hook.js +24 -24
  39. package/dist/bin/pushary-stopfailure-hook.js +24 -24
  40. package/dist/bin/pushary-suggestions.js +12 -12
  41. package/dist/bin/pushary-transcript-register.js +17 -17
  42. package/dist/bin/pushary-transcripts.js +7 -7
  43. package/dist/bin/pushary-upgrade.js +30 -30
  44. package/dist/bin/pushary-wait.js +12 -12
  45. package/dist/bin/pushary.js +6 -6
  46. package/dist/{chunk-4WGKAGIU.js → chunk-22YSHBTI.js} +3 -3
  47. package/dist/{chunk-IDGESFKZ.js → chunk-36ZCFJUI.js} +1 -1
  48. package/dist/{chunk-GROYT52D.js → chunk-3FOPVVNO.js} +4 -4
  49. package/dist/{chunk-5EX2SD5N.js → chunk-3LS3GFJW.js} +1 -1
  50. package/dist/{chunk-2ROXUEZV.js → chunk-45OXG3VR.js} +1 -1
  51. package/dist/{chunk-EPVY3JU3.js → chunk-4PIAOJAW.js} +1 -1
  52. package/dist/{chunk-AXANUGOV.js → chunk-4TFD3WAA.js} +2 -2
  53. package/dist/{chunk-35RJKPIC.js → chunk-57FFQR46.js} +1 -1
  54. package/dist/{chunk-FXJ5SEQT.js → chunk-6OGDGQTT.js} +5 -5
  55. package/dist/{chunk-TDLEFGAM.js → chunk-7FQL5NWJ.js} +117 -99
  56. package/dist/{chunk-SYUHM6V3.js → chunk-7IVV4LLF.js} +3 -3
  57. package/dist/{chunk-SAHD5DYW.js → chunk-7S7H7V5V.js} +4 -4
  58. package/dist/{chunk-SJJA2GPD.js → chunk-7UGGCTTW.js} +2 -2
  59. package/dist/{chunk-Q2GSTQ3R.js → chunk-A455TSHF.js} +2 -2
  60. package/dist/{chunk-CJCVPCOB.js → chunk-A5FFSXZE.js} +2 -2
  61. package/dist/{chunk-ALSIMOFS.js → chunk-B5RLJ6QD.js} +4 -4
  62. package/dist/{chunk-7447DYNW.js → chunk-CK3W7Q5S.js} +1 -1
  63. package/dist/{chunk-GSBOLJZ4.js → chunk-CPYOJRDN.js} +85 -48
  64. package/dist/{chunk-IKJJB4QG.js → chunk-DCBSD22V.js} +3 -3
  65. package/dist/{chunk-4JOWKPUF.js → chunk-DQKEGNTI.js} +1 -1
  66. package/dist/{chunk-D3TVRNZC.js → chunk-E2OZZZKP.js} +2 -2
  67. package/dist/{chunk-QGCEQGH6.js → chunk-EGTRIM74.js} +4 -4
  68. package/dist/{chunk-X5HK4XUN.js → chunk-EJWSE7S7.js} +5 -5
  69. package/dist/{chunk-N4LLBUU2.js → chunk-FDNMQEU6.js} +2 -2
  70. package/dist/{chunk-VFNYTVTJ.js → chunk-FPYBX36E.js} +5 -5
  71. package/dist/{chunk-OSUAY4SA.js → chunk-FQQSW7MD.js} +1 -1
  72. package/dist/{chunk-5F32ZTWD.js → chunk-FYQG2UTK.js} +2 -2
  73. package/dist/{chunk-QCOE42GO.js → chunk-GC3SUMYD.js} +4 -4
  74. package/dist/{chunk-FEICGRNI.js → chunk-H52HBSOD.js} +3 -3
  75. package/dist/{chunk-IIP4LEO3.js → chunk-HJNCVY5F.js} +7 -7
  76. package/dist/{chunk-H2PQXK26.js → chunk-HQKYWUBF.js} +2 -2
  77. package/dist/{chunk-BMUTA66M.js → chunk-HVUBWLER.js} +11 -11
  78. package/dist/{chunk-7S4Z36H7.js → chunk-IRU7DKJW.js} +3 -3
  79. package/dist/{chunk-3EIJDBVB.js → chunk-LOYSI2CZ.js} +5 -5
  80. package/dist/{chunk-MG523AVN.js → chunk-NKAMF2YJ.js} +1 -1
  81. package/dist/{chunk-KBRKQMCI.js → chunk-NMQLY4PE.js} +2 -2
  82. package/dist/{chunk-464FX6W5.js → chunk-OZMGO4WF.js} +6 -7
  83. package/dist/{chunk-77J4RVB2.js → chunk-PEEJP4HN.js} +4 -4
  84. package/dist/{chunk-OS6AE2MR.js → chunk-QJ3ENGBT.js} +3 -3
  85. package/dist/{chunk-X427XA76.js → chunk-SMRMWDFE.js} +8 -8
  86. package/dist/{chunk-MRR4NQ3H.js → chunk-SMSX4TCC.js} +1 -1
  87. package/dist/{chunk-SQIZGUAN.js → chunk-U7CN5HG2.js} +5 -5
  88. package/dist/{chunk-5FNE6ZVV.js → chunk-UDECNZYI.js} +2 -2
  89. package/dist/{chunk-NTWTU6FA.js → chunk-ULJFIF5N.js} +1 -1
  90. package/dist/{chunk-SRRJLA24.js → chunk-UPRNSD2T.js} +4 -4
  91. package/dist/{chunk-OTDRNEED.js → chunk-V4ZIG66K.js} +1 -1
  92. package/dist/{chunk-DP2FAIW6.js → chunk-VTAC5FBZ.js} +1 -1
  93. package/dist/{chunk-OULHOX5C.js → chunk-WFPXKCN4.js} +5 -5
  94. package/dist/{chunk-RN3KZDWP.js → chunk-WMB3OCI4.js} +2 -2
  95. package/dist/{chunk-75UCMLT5.js → chunk-WPSI4246.js} +1 -1
  96. package/dist/{chunk-ZYDSHR5P.js → chunk-XLXG6MA5.js} +3 -3
  97. package/dist/{chunk-5GDNIEL5.js → chunk-YABMIGR3.js} +1 -1
  98. package/dist/{chunk-FGFFUCEL.js → chunk-YRDNKY77.js} +6 -6
  99. package/dist/{chunk-Q7H2IMJQ.js → chunk-Z6HDYK2A.js} +2 -2
  100. package/dist/{global-upgrade-YMBTZHDP.js → global-upgrade-IZCB4WIE.js} +6 -6
  101. package/dist/{paths-BPFRUWMB.js → paths-4WAA57P5.js} +2 -2
  102. package/dist/{reapply-ZC2LSUVZ.js → reapply-GJ73ZHDD.js} +20 -20
  103. package/dist/src/index.js +19 -19
  104. package/dist/{upgrade-lock-TTZMLZPB.js → upgrade-lock-J5PIKSYV.js} +3 -3
  105. package/package.json +1 -1
@@ -16,7 +16,7 @@ var COWORK_STANDING_INSTRUCTIONS = `Pushary is connected as a custom connector.
16
16
  - Before a risky or irreversible action outside my existing authorization, call ask_user with type "confirm" and wait for approval. Silence is never consent.
17
17
  - When a task finishes, call send_notification with context.type "task_complete" and a short summary. For an error you cannot resolve, use context.type "error"; use "info" for other updates.
18
18
  - Only keep a reply channel open when a specific unresolved decision is required: call send_notification with context.askQuestion, then poll the returned linkedCorrelationId with wait_for_answer. Do not ask for optional feedback just to keep a finished turn alive.
19
- - Follow handoffAction when present, otherwise nextAction. If ask_user times out on a live question, poll once with wait_for_answer. If still pending, cancel_question before asking in the current chat. If cancellation returns handoffAction "stop", stop. If cancellation returns false, poll once for 1 second and honor the answer that won the race. Expired, cancelled, missing, and unavailable questions are not new timeouts.
19
+ - Follow handoffAction when present, otherwise nextAction. While pending, keep waiting with the same correlationId. Only for an explicit handoff, cancel_question before asking in the current chat. If cancellation returns handoffAction "stop", stop. If cancellation returns false, poll once for 1 second and honor the answer that won the race. Expired, cancelled, missing, and unavailable questions are not new timeouts.
20
20
  - Pass agentName as "Claude Cowork - <task name>" on every call, and reuse one opaque sessionId per task so parallel tasks stay separate. Never include credentials in these identifiers.
21
21
  - Cancel a question when it is no longer needed. Once this turn ends, reopen Cowork for follow-up work; this connector cannot restart it.
22
22
  - If Pushary tools are missing or disabled, report that once and continue within my authorization. Do not claim a notification or approval was delivered.`;
@@ -1758,6 +1758,8 @@ var STATEMENT_SEPARATOR2 = ";";
1758
1758
  var SINGLE_QUOTE = "'";
1759
1759
  var DOUBLE_QUOTE = '"';
1760
1760
  var BACKTICK = "`";
1761
+ var BRACKET_IDENTIFIER_OPEN = "[";
1762
+ var BRACKET_IDENTIFIER_CLOSE = "]";
1761
1763
  var BACKSLASH = "\\";
1762
1764
  var DOLLAR = "$";
1763
1765
  var DASH_DASH = "--";
@@ -1877,6 +1879,7 @@ var swallowsABacktick = (source, start, end, lexicon) => {
1877
1879
  return false;
1878
1880
  };
1879
1881
  var unterminatedTextRunsToTheEnd = (reading) => reading.backslashMode === "literal";
1882
+ var visibleQuotedText = (content) => `${TOKEN_GAP}${content}${TOKEN_GAP}`;
1880
1883
  var quotedToken = (source, start, reading, inside) => {
1881
1884
  if (opensAUnicodeEscapedQuote(source, start)) return "uncertain";
1882
1885
  const syntax = syntaxOfQuoteAt(source, start, reading.lexicon);
@@ -1888,7 +1891,7 @@ var quotedToken = (source, start, reading, inside) => {
1888
1891
  }
1889
1892
  if (swallowsABacktick(source, start, end, reading.lexicon)) return "uncertain";
1890
1893
  const quote = source.charAt(start);
1891
- const text = syntax.content === "hidden" ? STRING_PLACEHOLDER : source.slice(start + opener.length, end - opener.length).replaceAll(quote + quote, quote);
1894
+ const text = syntax.content === "hidden" ? STRING_PLACEHOLDER : visibleQuotedText(source.slice(start + opener.length, end - opener.length).replaceAll(quote + quote, quote));
1892
1895
  return { text, end, insideExecutableComment: inside };
1893
1896
  };
1894
1897
  var lineCommentEnd = (source, start, lexicon) => {
@@ -1951,9 +1954,16 @@ var clientCommandToken = (source, start, inside) => {
1951
1954
  const command = source.slice(start, start + CLIENT_COMMAND_LENGTH);
1952
1955
  return STATEMENT_TERMINATOR_CLIENT_COMMAND.test(command) ? { text: STATEMENT_SEPARATOR2, end: start + CLIENT_COMMAND_LENGTH, insideExecutableComment: inside } : "uncertain";
1953
1956
  };
1957
+ var squareBracketToken = (source, start, lexicon, inside) => {
1958
+ if (lexicon.squareBrackets === "uncertain") return "uncertain";
1959
+ if (lexicon.squareBrackets === "text") return { text: BRACKET_IDENTIFIER_OPEN, end: start + 1, insideExecutableComment: inside };
1960
+ const closing = source.indexOf(BRACKET_IDENTIFIER_CLOSE, start + 1);
1961
+ return closing === -1 ? "uncertain" : { text: visibleQuotedText(source.slice(start + 1, closing)), end: closing + 1, insideExecutableComment: inside };
1962
+ };
1954
1963
  var nextSqlToken = (source, start, reading, inside) => {
1955
1964
  const { lexicon } = reading;
1956
1965
  const character = source.charAt(start);
1966
+ if (character === BRACKET_IDENTIFIER_OPEN) return squareBracketToken(source, start, lexicon, inside);
1957
1967
  if (isQuote(character)) return quotedToken(source, start, reading, inside);
1958
1968
  if (source.startsWith(DASH_DASH, start)) return dashDashToken(source, start, lexicon, inside);
1959
1969
  if (character === HASH) return hashToken(source, start, lexicon, inside);
@@ -1993,6 +2003,107 @@ var sqlOutsideLiterals = (source, lexicon) => {
1993
2003
  return { kind: "readable", texts: [...new Set(readings.map((reading) => reading.text))] };
1994
2004
  };
1995
2005
 
2006
+ // ../contracts/src/command-analysis/sql-clients.ts
2007
+ var STRING_WITH_DOUBLED_QUOTES = { backslashes: "uncertain-before-the-quote", content: "hidden" };
2008
+ var IDENTIFIER_WITH_DOUBLED_QUOTES = { backslashes: "uncertain-before-the-quote", content: "shown" };
2009
+ var MYSQL_STRING = { backslashes: "escape-unless-the-sql-mode-disables-it", content: "hidden" };
2010
+ var STRING_WITH_BACKSLASH_ESCAPES = { backslashes: "escape", content: "hidden" };
2011
+ var SHOWN_TEXT_WITH_BACKSLASH_ESCAPES = { backslashes: "escape", content: "shown" };
2012
+ var POSTGRES_LEXICON = {
2013
+ squareBrackets: "text",
2014
+ singleQuotes: STRING_WITH_DOUBLED_QUOTES,
2015
+ doubleQuotes: IDENTIFIER_WITH_DOUBLED_QUOTES,
2016
+ backticks: IDENTIFIER_WITH_DOUBLED_QUOTES,
2017
+ tripleQuotes: "absent",
2018
+ escapeStringPrefix: "backslash-escapes",
2019
+ dollarQuotes: "string",
2020
+ dashDash: "comment",
2021
+ carriageReturnInLineComment: "ends-the-comment",
2022
+ hash: "text",
2023
+ executableComments: "uncertain",
2024
+ nestedBlockComments: "nest",
2025
+ backslashOutsideLiterals: "text",
2026
+ clientCharsets: "may-be-multibyte"
2027
+ };
2028
+ var MYSQL_LEXICON = {
2029
+ squareBrackets: "uncertain",
2030
+ singleQuotes: MYSQL_STRING,
2031
+ doubleQuotes: STRING_WITH_DOUBLED_QUOTES,
2032
+ backticks: IDENTIFIER_WITH_DOUBLED_QUOTES,
2033
+ tripleQuotes: "absent",
2034
+ escapeStringPrefix: "absent",
2035
+ dollarQuotes: "uncertain",
2036
+ dashDash: "comment-before-whitespace",
2037
+ carriageReturnInLineComment: "stays-in-the-comment",
2038
+ hash: "comment",
2039
+ executableComments: "executed",
2040
+ nestedBlockComments: "uncertain",
2041
+ backslashOutsideLiterals: "client-command",
2042
+ clientCharsets: "may-be-multibyte"
2043
+ };
2044
+ var SQLITE_LEXICON = {
2045
+ squareBrackets: "identifier",
2046
+ singleQuotes: STRING_WITH_DOUBLED_QUOTES,
2047
+ doubleQuotes: IDENTIFIER_WITH_DOUBLED_QUOTES,
2048
+ backticks: IDENTIFIER_WITH_DOUBLED_QUOTES,
2049
+ tripleQuotes: "absent",
2050
+ escapeStringPrefix: "absent",
2051
+ dollarQuotes: "uncertain",
2052
+ dashDash: "comment",
2053
+ carriageReturnInLineComment: "stays-in-the-comment",
2054
+ hash: "text",
2055
+ executableComments: "uncertain",
2056
+ nestedBlockComments: "uncertain",
2057
+ backslashOutsideLiterals: "text",
2058
+ clientCharsets: "unicode"
2059
+ };
2060
+ var GOOGLE_SQL_LEXICON = {
2061
+ squareBrackets: "text",
2062
+ singleQuotes: STRING_WITH_BACKSLASH_ESCAPES,
2063
+ doubleQuotes: SHOWN_TEXT_WITH_BACKSLASH_ESCAPES,
2064
+ backticks: SHOWN_TEXT_WITH_BACKSLASH_ESCAPES,
2065
+ tripleQuotes: "quote",
2066
+ escapeStringPrefix: "absent",
2067
+ dollarQuotes: "uncertain",
2068
+ dashDash: "comment",
2069
+ carriageReturnInLineComment: "uncertain",
2070
+ hash: "comment",
2071
+ executableComments: "uncertain",
2072
+ nestedBlockComments: "uncertain",
2073
+ backslashOutsideLiterals: "text",
2074
+ clientCharsets: "unicode"
2075
+ };
2076
+ var UNVERIFIED_SQL_LEXICON = {
2077
+ squareBrackets: "uncertain",
2078
+ singleQuotes: STRING_WITH_DOUBLED_QUOTES,
2079
+ doubleQuotes: IDENTIFIER_WITH_DOUBLED_QUOTES,
2080
+ backticks: IDENTIFIER_WITH_DOUBLED_QUOTES,
2081
+ tripleQuotes: "absent",
2082
+ escapeStringPrefix: "absent",
2083
+ dollarQuotes: "uncertain",
2084
+ dashDash: "uncertain-before-text",
2085
+ carriageReturnInLineComment: "uncertain",
2086
+ hash: "uncertain",
2087
+ executableComments: "uncertain",
2088
+ nestedBlockComments: "uncertain",
2089
+ backslashOutsideLiterals: "text",
2090
+ clientCharsets: "may-be-multibyte"
2091
+ };
2092
+ var MYSQL_SYNTAX = { inlineFlags: /* @__PURE__ */ new Set(["-e", "--execute"]), scriptFlags: /* @__PURE__ */ new Set(), positionalSql: false, lexicon: MYSQL_LEXICON };
2093
+ var SQLITE_SYNTAX = { inlineFlags: /* @__PURE__ */ new Set(["-cmd"]), scriptFlags: /* @__PURE__ */ new Set(["-init"]), positionalSql: true, lexicon: SQLITE_LEXICON };
2094
+ var SQL_CLIENT_SYNTAX = /* @__PURE__ */ new Map([
2095
+ ["psql", { inlineFlags: /* @__PURE__ */ new Set(["-c", "--command"]), scriptFlags: /* @__PURE__ */ new Set(["-f", "--file"]), positionalSql: false, lexicon: POSTGRES_LEXICON }],
2096
+ ["mysql", MYSQL_SYNTAX],
2097
+ ["mariadb", MYSQL_SYNTAX],
2098
+ ["sqlite3", SQLITE_SYNTAX],
2099
+ ["sqlite", SQLITE_SYNTAX],
2100
+ ["duckdb", { inlineFlags: /* @__PURE__ */ new Set(["-c", "-s", "-cmd"]), scriptFlags: /* @__PURE__ */ new Set(["-f", "-init"]), positionalSql: true, lexicon: UNVERIFIED_SQL_LEXICON }],
2101
+ ["clickhouse-client", { inlineFlags: /* @__PURE__ */ new Set(["-q", "--query"]), scriptFlags: /* @__PURE__ */ new Set(["--queries-file"]), positionalSql: false, lexicon: UNVERIFIED_SQL_LEXICON }],
2102
+ ["bq", { inlineFlags: /* @__PURE__ */ new Set(), scriptFlags: /* @__PURE__ */ new Set(), positionalSql: true, lexicon: GOOGLE_SQL_LEXICON }],
2103
+ ["mongosh", { inlineFlags: /* @__PURE__ */ new Set(["--eval"]), scriptFlags: /* @__PURE__ */ new Set(["-f", "--file"]), positionalSql: false, lexicon: UNVERIFIED_SQL_LEXICON }],
2104
+ ["mongo", { inlineFlags: /* @__PURE__ */ new Set(["--eval"]), scriptFlags: /* @__PURE__ */ new Set(), positionalSql: false, lexicon: UNVERIFIED_SQL_LEXICON }]
2105
+ ]);
2106
+
1996
2107
  // ../contracts/src/command-analysis/env-invocation.ts
1997
2108
  var GNU_ENV = {
1998
2109
  shortOptions: { switches: /* @__PURE__ */ new Set(["i", "v", "0"]), withAValue: /* @__PURE__ */ new Set(["a", "C", "S", "u"]) },
@@ -2291,6 +2402,9 @@ var MIN_SAFE_CLI_VERSION = formatReleaseVersion(MIN_SAFE_RELEASE);
2291
2402
  var AUTO_UPDATE_RESULTS = ["updated", "current", "needs_manual", "failed", "finish_pending", "finish_blocked"];
2292
2403
  var isAutoUpdateResult = (value) => typeof value === "string" && AUTO_UPDATE_RESULTS.includes(value);
2293
2404
 
2405
+ // ../contracts/src/answer-drafts.ts
2406
+ var ANSWER_DRAFT_TTL_MS = 24 * 60 * 60 * 1e3;
2407
+
2294
2408
  // ../contracts/src/index.ts
2295
2409
  var KEY_SCOPES = ["full_access", "agent", "connector", "bound"];
2296
2410
  var normalizeKeyScope = (value) => typeof value === "string" && KEY_SCOPES.includes(value) ? value : null;
@@ -3315,100 +3429,6 @@ var changesProduction = (invocation) => {
3315
3429
  const words = wordsOfInvocation(invocation);
3316
3430
  return words.some((word, index) => wordSelectsProduction(word, words[index - 1])) && (deployCliChangesSomething(words) || SCHEMA_CHANGE_WORD.test(normalizedInvocation(invocation)));
3317
3431
  };
3318
- var STRING_WITH_DOUBLED_QUOTES = { backslashes: "uncertain-before-the-quote", content: "hidden" };
3319
- var IDENTIFIER_WITH_DOUBLED_QUOTES = { backslashes: "uncertain-before-the-quote", content: "shown" };
3320
- var MYSQL_STRING = { backslashes: "escape-unless-the-sql-mode-disables-it", content: "hidden" };
3321
- var STRING_WITH_BACKSLASH_ESCAPES = { backslashes: "escape", content: "hidden" };
3322
- var SHOWN_TEXT_WITH_BACKSLASH_ESCAPES = { backslashes: "escape", content: "shown" };
3323
- var POSTGRES_LEXICON = {
3324
- singleQuotes: STRING_WITH_DOUBLED_QUOTES,
3325
- doubleQuotes: IDENTIFIER_WITH_DOUBLED_QUOTES,
3326
- backticks: IDENTIFIER_WITH_DOUBLED_QUOTES,
3327
- tripleQuotes: "absent",
3328
- escapeStringPrefix: "backslash-escapes",
3329
- dollarQuotes: "string",
3330
- dashDash: "comment",
3331
- carriageReturnInLineComment: "ends-the-comment",
3332
- hash: "text",
3333
- executableComments: "uncertain",
3334
- nestedBlockComments: "nest",
3335
- backslashOutsideLiterals: "text",
3336
- clientCharsets: "may-be-multibyte"
3337
- };
3338
- var MYSQL_LEXICON = {
3339
- singleQuotes: MYSQL_STRING,
3340
- doubleQuotes: STRING_WITH_DOUBLED_QUOTES,
3341
- backticks: IDENTIFIER_WITH_DOUBLED_QUOTES,
3342
- tripleQuotes: "absent",
3343
- escapeStringPrefix: "absent",
3344
- dollarQuotes: "uncertain",
3345
- dashDash: "comment-before-whitespace",
3346
- carriageReturnInLineComment: "stays-in-the-comment",
3347
- hash: "comment",
3348
- executableComments: "executed",
3349
- nestedBlockComments: "uncertain",
3350
- backslashOutsideLiterals: "client-command",
3351
- clientCharsets: "may-be-multibyte"
3352
- };
3353
- var SQLITE_LEXICON = {
3354
- singleQuotes: STRING_WITH_DOUBLED_QUOTES,
3355
- doubleQuotes: IDENTIFIER_WITH_DOUBLED_QUOTES,
3356
- backticks: IDENTIFIER_WITH_DOUBLED_QUOTES,
3357
- tripleQuotes: "absent",
3358
- escapeStringPrefix: "absent",
3359
- dollarQuotes: "uncertain",
3360
- dashDash: "comment",
3361
- carriageReturnInLineComment: "stays-in-the-comment",
3362
- hash: "text",
3363
- executableComments: "uncertain",
3364
- nestedBlockComments: "uncertain",
3365
- backslashOutsideLiterals: "text",
3366
- clientCharsets: "unicode"
3367
- };
3368
- var GOOGLE_SQL_LEXICON = {
3369
- singleQuotes: STRING_WITH_BACKSLASH_ESCAPES,
3370
- doubleQuotes: SHOWN_TEXT_WITH_BACKSLASH_ESCAPES,
3371
- backticks: SHOWN_TEXT_WITH_BACKSLASH_ESCAPES,
3372
- tripleQuotes: "quote",
3373
- escapeStringPrefix: "absent",
3374
- dollarQuotes: "uncertain",
3375
- dashDash: "comment",
3376
- carriageReturnInLineComment: "uncertain",
3377
- hash: "comment",
3378
- executableComments: "uncertain",
3379
- nestedBlockComments: "uncertain",
3380
- backslashOutsideLiterals: "text",
3381
- clientCharsets: "unicode"
3382
- };
3383
- var UNVERIFIED_SQL_LEXICON = {
3384
- singleQuotes: STRING_WITH_DOUBLED_QUOTES,
3385
- doubleQuotes: IDENTIFIER_WITH_DOUBLED_QUOTES,
3386
- backticks: IDENTIFIER_WITH_DOUBLED_QUOTES,
3387
- tripleQuotes: "absent",
3388
- escapeStringPrefix: "absent",
3389
- dollarQuotes: "uncertain",
3390
- dashDash: "uncertain-before-text",
3391
- carriageReturnInLineComment: "uncertain",
3392
- hash: "uncertain",
3393
- executableComments: "uncertain",
3394
- nestedBlockComments: "uncertain",
3395
- backslashOutsideLiterals: "text",
3396
- clientCharsets: "may-be-multibyte"
3397
- };
3398
- var MYSQL_SYNTAX = { inlineFlags: /* @__PURE__ */ new Set(["-e", "--execute"]), scriptFlags: /* @__PURE__ */ new Set(), positionalSql: false, lexicon: MYSQL_LEXICON };
3399
- var SQLITE_SYNTAX = { inlineFlags: /* @__PURE__ */ new Set(["-cmd"]), scriptFlags: /* @__PURE__ */ new Set(["-init"]), positionalSql: true, lexicon: SQLITE_LEXICON };
3400
- var SQL_CLIENT_SYNTAX = /* @__PURE__ */ new Map([
3401
- ["psql", { inlineFlags: /* @__PURE__ */ new Set(["-c", "--command"]), scriptFlags: /* @__PURE__ */ new Set(["-f", "--file"]), positionalSql: false, lexicon: POSTGRES_LEXICON }],
3402
- ["mysql", MYSQL_SYNTAX],
3403
- ["mariadb", MYSQL_SYNTAX],
3404
- ["sqlite3", SQLITE_SYNTAX],
3405
- ["sqlite", SQLITE_SYNTAX],
3406
- ["duckdb", { inlineFlags: /* @__PURE__ */ new Set(["-c", "-s", "-cmd"]), scriptFlags: /* @__PURE__ */ new Set(["-f", "-init"]), positionalSql: true, lexicon: UNVERIFIED_SQL_LEXICON }],
3407
- ["clickhouse-client", { inlineFlags: /* @__PURE__ */ new Set(["-q", "--query"]), scriptFlags: /* @__PURE__ */ new Set(["--queries-file"]), positionalSql: false, lexicon: UNVERIFIED_SQL_LEXICON }],
3408
- ["bq", { inlineFlags: /* @__PURE__ */ new Set(), scriptFlags: /* @__PURE__ */ new Set(), positionalSql: true, lexicon: GOOGLE_SQL_LEXICON }],
3409
- ["mongosh", { inlineFlags: /* @__PURE__ */ new Set(["--eval"]), scriptFlags: /* @__PURE__ */ new Set(["-f", "--file"]), positionalSql: false, lexicon: UNVERIFIED_SQL_LEXICON }],
3410
- ["mongo", { inlineFlags: /* @__PURE__ */ new Set(["--eval"]), scriptFlags: /* @__PURE__ */ new Set(), positionalSql: false, lexicon: UNVERIFIED_SQL_LEXICON }]
3411
- ]);
3412
3432
  var SQL_WRITE_STATEMENT = new RegExp([
3413
3433
  String.raw`\b(?:insert|update|delete|merge|upsert|alter|create|drop|truncate|grant|revoke|copy|vacuum|reindex|rename|attach|detach)\b`,
3414
3434
  String.raw`\breplace\s+into\b`,
@@ -3781,7 +3801,7 @@ var segmentWritesThroughARemoteApi = (segment, depth) => {
3781
3801
  const innermost = innermostInvocation(segment.invocation);
3782
3802
  return invocationWritesThroughARemoteApi(innermost) || commandsNestedIn(innermost, inlineScriptsOf(innermost, segment.heredocs)).some((nested) => commandWritesThroughARemoteApiAt(nested, depth + 1));
3783
3803
  };
3784
- var commandWritesThroughARemoteApiAt = (command, depth) => depth <= MAX_SPELLING_DEPTH && spelledSegmentsOf(command).some((segment) => segmentWritesThroughARemoteApi(segment, depth));
3804
+ var commandWritesThroughARemoteApiAt = (command, depth) => depth > MAX_SPELLING_DEPTH || spelledSegmentsOf(command).some((segment) => segmentWritesThroughARemoteApi(segment, depth));
3785
3805
  var commandWritesThroughARemoteApi = (command) => commandWritesThroughARemoteApiAt(command, 0);
3786
3806
  var segmentNeedsAPerson = (toolName, segment) => {
3787
3807
  const invocation = invocationOf(segment);
@@ -4463,7 +4483,6 @@ var API_KEY_PATTERN = new RegExp(`^${API_KEY_PREFIX_SHAPE}\\.[a-f0-9]+$`);
4463
4483
  var isValidApiKey = (value) => API_KEY_PATTERN.test(value);
4464
4484
  var ACTION_BODY_MAX = 4e3;
4465
4485
  var DECISION_LINE_MAX = 500;
4466
- var ASK_QUESTION_MAX = 500;
4467
4486
  var ASK_AGENT_NAME_MAX = 100;
4468
4487
  var TRUNCATION_MARK = "\u2026";
4469
4488
  var isHighSurrogate = (code) => code >= 55296 && code <= 56319;
@@ -5846,7 +5865,6 @@ export {
5846
5865
  isValidApiKey,
5847
5866
  ACTION_BODY_MAX,
5848
5867
  DECISION_LINE_MAX,
5849
- ASK_QUESTION_MAX,
5850
5868
  ASK_AGENT_NAME_MAX,
5851
5869
  truncateLine,
5852
5870
  isAnswerSource,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  pusharyFetch
3
- } from "./chunk-4WGKAGIU.js";
3
+ } from "./chunk-22YSHBTI.js";
4
4
  import {
5
5
  NetworkError
6
6
  } from "./chunk-7QLSKOSU.js";
@@ -9,11 +9,11 @@ import {
9
9
  } from "./chunk-KZERVKTD.js";
10
10
  import {
11
11
  getBaseUrl
12
- } from "./chunk-5EX2SD5N.js";
12
+ } from "./chunk-3LS3GFJW.js";
13
13
  import {
14
14
  isValidApiKey,
15
15
  normalizeKeyScope
16
- } from "./chunk-TDLEFGAM.js";
16
+ } from "./chunk-7FQL5NWJ.js";
17
17
 
18
18
  // src/session.ts
19
19
  var samePusharyAccount = (left, right) => left.kind === "ok" && right.kind === "ok" && left.identity.workspaceId !== "" && left.identity.workspaceId === right.identity.workspaceId && left.identity.siteId === right.identity.siteId;
@@ -3,18 +3,18 @@ import {
3
3
  addGeminiMcpServer,
4
4
  removeGeminiMcpServer,
5
5
  supportedClaudeEvents
6
- } from "./chunk-OS6AE2MR.js";
6
+ } from "./chunk-QJ3ENGBT.js";
7
7
  import {
8
8
  CLAUDE_CODE_AGENT,
9
9
  parseApplyPatchFiles
10
- } from "./chunk-X427XA76.js";
10
+ } from "./chunk-SMRMWDFE.js";
11
11
  import {
12
12
  guardBinary,
13
13
  guardBinaryRefusing,
14
14
  holdBudgetOf,
15
15
  isProtectedByScope,
16
16
  registerHookEntry
17
- } from "./chunk-SRRJLA24.js";
17
+ } from "./chunk-UPRNSD2T.js";
18
18
  import {
19
19
  HOOK_LOCATOR_BINARY,
20
20
  PHONE_ANSWERED_TOOLS,
@@ -24,7 +24,7 @@ import {
24
24
  refusalOutput,
25
25
  toToolLookup,
26
26
  withHookHoldBudget
27
- } from "./chunk-TDLEFGAM.js";
27
+ } from "./chunk-7FQL5NWJ.js";
28
28
 
29
29
  // src/claude-config.ts
30
30
  import { join } from "path";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-POFBE6ZY.js";
4
4
  import {
5
5
  autoUpdateState
6
- } from "./chunk-SRRJLA24.js";
6
+ } from "./chunk-UPRNSD2T.js";
7
7
  import {
8
8
  readJsonSafe,
9
9
  writeJsonAtomic
@@ -15,7 +15,7 @@ import {
15
15
  globalUpgradeEntry,
16
16
  isAutoUpdateResult,
17
17
  ownPackageRoot
18
- } from "./chunk-TDLEFGAM.js";
18
+ } from "./chunk-7FQL5NWJ.js";
19
19
 
20
20
  // src/auto-update.ts
21
21
  import { spawn } from "child_process";
@@ -8,10 +8,10 @@ import {
8
8
  codexHooksJsonIn,
9
9
  isPusharyCodexCommand,
10
10
  resolvePathBinary
11
- } from "./chunk-SRRJLA24.js";
11
+ } from "./chunk-UPRNSD2T.js";
12
12
  import {
13
13
  getPackageVersion
14
- } from "./chunk-TDLEFGAM.js";
14
+ } from "./chunk-7FQL5NWJ.js";
15
15
 
16
16
  // src/codex-app-server.ts
17
17
  import { existsSync, realpathSync } from "fs";
@@ -3,10 +3,10 @@ import {
3
3
  } from "./chunk-KZERVKTD.js";
4
4
  import {
5
5
  renderCommandHelp
6
- } from "./chunk-2ROXUEZV.js";
6
+ } from "./chunk-45OXG3VR.js";
7
7
  import {
8
8
  getPackageVersion
9
- } from "./chunk-TDLEFGAM.js";
9
+ } from "./chunk-7FQL5NWJ.js";
10
10
 
11
11
  // src/cli/usage.ts
12
12
  var exitOnHelpFlag = (command) => {
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  registerTranscript
3
- } from "./chunk-GSBOLJZ4.js";
3
+ } from "./chunk-CPYOJRDN.js";
4
4
  import {
5
5
  namedEvent
6
- } from "./chunk-SAHD5DYW.js";
6
+ } from "./chunk-7S7H7V5V.js";
7
7
  import {
8
8
  writeDegraded
9
- } from "./chunk-464FX6W5.js";
9
+ } from "./chunk-OZMGO4WF.js";
10
10
  import {
11
11
  claudeShapedHookInput,
12
12
  hookCompatibleProfileBySource
13
- } from "./chunk-TDLEFGAM.js";
13
+ } from "./chunk-7FQL5NWJ.js";
14
14
 
15
15
  // src/tool-hook-input.ts
16
16
  var OPTIONAL_TEXT_FIELDS = ["hook_event_name", "session_id", "cwd", "transcript_path", "tool_use_id", "permission_mode"];
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  redactSecretsFromContent
3
- } from "./chunk-TDLEFGAM.js";
3
+ } from "./chunk-7FQL5NWJ.js";
4
4
 
5
5
  // src/crypto.ts
6
6
  import nacl from "tweetnacl";
@@ -6,38 +6,38 @@ import {
6
6
  } from "./chunk-DWQYCOPI.js";
7
7
  import {
8
8
  ensureDaemonRunning
9
- } from "./chunk-VFNYTVTJ.js";
9
+ } from "./chunk-FPYBX36E.js";
10
10
  import {
11
11
  buildTranscriptRecords,
12
12
  decodePublicKey,
13
13
  generateSessionKey,
14
14
  wrapSessionKey
15
- } from "./chunk-7447DYNW.js";
15
+ } from "./chunk-CK3W7Q5S.js";
16
16
  import {
17
17
  fetchTranscriptRecipients,
18
18
  uploadTranscriptRecords
19
- } from "./chunk-EPVY3JU3.js";
19
+ } from "./chunk-4PIAOJAW.js";
20
20
  import {
21
21
  transcriptEnvironmentPreference,
22
22
  transcriptsEnabled
23
- } from "./chunk-MRR4NQ3H.js";
23
+ } from "./chunk-SMSX4TCC.js";
24
24
  import {
25
25
  hookOwnerOf
26
- } from "./chunk-FXJ5SEQT.js";
26
+ } from "./chunk-6OGDGQTT.js";
27
27
  import {
28
28
  readTranscriptPreference
29
- } from "./chunk-IKJJB4QG.js";
29
+ } from "./chunk-DCBSD22V.js";
30
30
  import {
31
31
  codexHome,
32
32
  pusharyDir
33
- } from "./chunk-SRRJLA24.js";
33
+ } from "./chunk-UPRNSD2T.js";
34
34
  import {
35
35
  writeJsonAtomic
36
36
  } from "./chunk-AQFEP65J.js";
37
37
  import {
38
38
  getApiKey,
39
39
  getBaseUrl
40
- } from "./chunk-5EX2SD5N.js";
40
+ } from "./chunk-3LS3GFJW.js";
41
41
 
42
42
  // src/transcript-registration.ts
43
43
  import { createHash } from "crypto";
@@ -176,27 +176,30 @@ var createSyncState = () => ({
176
176
  seen: /* @__PURE__ */ new Set(),
177
177
  keyUploaded: false,
178
178
  keyRejected: false,
179
- keyUnavailable: false
179
+ keyUnavailable: false,
180
+ unsettled: 0
180
181
  });
182
+ var withSessionKey = async (state, uploader) => {
183
+ if (state.sessionKey || state.keyRejected) return state;
184
+ const recipients = await uploader.fetchTranscriptRecipients();
185
+ if (!recipients) return state;
186
+ const sessionKey = generateSessionKey();
187
+ return {
188
+ ...state,
189
+ sessionKey,
190
+ wrappedKey: wrapSessionKey(sessionKey, decodePublicKey(recipients.phonePublicKey)),
191
+ providerWrappedKey: recipients.provider ? wrapSessionKey(sessionKey, decodePublicKey(recipients.provider.publicKey)) : state.providerWrappedKey,
192
+ providerKeyId: recipients.provider ? recipients.provider.keyId : state.providerKeyId
193
+ };
194
+ };
181
195
  var syncTick = async (lines, state, uploader, sessionId, machineId) => {
182
196
  if (state.keyRejected) return state;
183
- let sessionKey = state.sessionKey;
184
- let wrappedKey = state.wrappedKey;
185
- let providerWrappedKey = state.providerWrappedKey;
186
- let providerKeyId = state.providerKeyId;
187
- if (!sessionKey) {
188
- const recipients = await uploader.fetchTranscriptRecipients();
189
- if (!recipients) return state;
190
- sessionKey = generateSessionKey();
191
- wrappedKey = wrapSessionKey(sessionKey, decodePublicKey(recipients.phonePublicKey));
192
- if (recipients.provider) {
193
- providerWrappedKey = wrapSessionKey(sessionKey, decodePublicKey(recipients.provider.publicKey));
194
- providerKeyId = recipients.provider.keyId;
195
- }
196
- }
197
+ const keyed = await withSessionKey(state, uploader);
198
+ const { sessionKey, wrappedKey, providerWrappedKey, providerKeyId } = keyed;
199
+ if (!sessionKey) return state;
197
200
  const built = buildTranscriptRecords(lines, sessionKey, state.seen);
198
201
  if (built.records.length === 0) {
199
- return { ...state, sessionKey, wrappedKey, providerWrappedKey, providerKeyId, seen: built.seen };
202
+ return { ...state, sessionKey, wrappedKey, providerWrappedKey, providerKeyId, seen: built.seen, unsettled: 0 };
200
203
  }
201
204
  const seen = new Set(state.seen);
202
205
  let keyUploaded = state.keyUploaded;
@@ -237,7 +240,8 @@ var syncTick = async (lines, state, uploader, sessionId, machineId) => {
237
240
  seen,
238
241
  keyUploaded,
239
242
  keyRejected,
240
- keyUnavailable
243
+ keyUnavailable,
244
+ unsettled: built.records.filter((record) => !seen.has(record.localId)).length
241
245
  };
242
246
  };
243
247
  var MAX_RECORDS_PER_BATCH = 200;
@@ -299,7 +303,19 @@ var statOrNull = (path) => {
299
303
  };
300
304
  var sightTranscript = (epoch, path, seenAtMs) => recordSighting(epoch, path, sightingOf(statOrNull(path), seenAtMs));
301
305
  var LINE_FEED = 10;
302
- var nothingUnread = (cutoff) => ({ lines: [], cutoff, completeThroughOffset: cutoff.offset });
306
+ var MAXIMUM_TRANSCRIPT_READ_BYTES = 4 * 1024 * 1024;
307
+ var CATCH_UP_DELAY_MS = 50;
308
+ var STALLED_BACKOFF_FACTOR = 4;
309
+ var nothingUnread = (cutoff) => ({ lines: [], cutoff, completeThroughOffset: cutoff.offset, reachedEnd: true });
310
+ var readThroughALineEnd = (descriptor, offset, unread) => {
311
+ let window = Math.min(unread, MAXIMUM_TRANSCRIPT_READ_BYTES);
312
+ for (; ; ) {
313
+ const buffer = Buffer.alloc(window);
314
+ const received = buffer.subarray(0, readSync(descriptor, buffer, 0, window, offset));
315
+ if (window >= unread || received.length < window || received.includes(LINE_FEED)) return received;
316
+ window = Math.min(unread, window * 2);
317
+ }
318
+ };
303
319
  var readLinesSinceCutoff = (epoch, path, seenAtMs) => {
304
320
  let descriptor;
305
321
  try {
@@ -312,12 +328,14 @@ var readLinesSinceCutoff = (epoch, path, seenAtMs) => {
312
328
  const cutoff = recordSighting(epoch, path, sightingOf(info, seenAtMs));
313
329
  const unread = info.size - cutoff.offset;
314
330
  if (unread <= 0) return nothingUnread(cutoff);
315
- const buffer = Buffer.alloc(unread);
316
- const received = buffer.subarray(0, readSync(descriptor, buffer, 0, unread, cutoff.offset));
331
+ const received = readThroughALineEnd(descriptor, cutoff.offset, unread);
332
+ const completeBytes = received.lastIndexOf(LINE_FEED) + 1;
333
+ const reachedEnd = received.length >= unread;
317
334
  return {
318
- lines: received.toString("utf8").split("\n"),
335
+ lines: (reachedEnd ? received : received.subarray(0, completeBytes)).toString("utf8").split("\n"),
319
336
  cutoff,
320
- completeThroughOffset: cutoff.offset + received.lastIndexOf(LINE_FEED) + 1
337
+ completeThroughOffset: cutoff.offset + completeBytes,
338
+ reachedEnd
321
339
  };
322
340
  } finally {
323
341
  closeSync(descriptor);
@@ -327,7 +345,8 @@ var linesSeenDuringEpoch = (epoch, path, source, seenAtMs) => {
327
345
  const read2 = readLinesSinceCutoff(epoch, path, seenAtMs);
328
346
  return { ...read2, lines: transcriptLinesSeenLive(normalizeTranscriptLines(read2.lines, source), epoch.startedAtMs, read2.cutoff.startedBeforeEpoch) };
329
347
  };
330
- var nothingLeftToUpload = (state, lines) => state.sessionKey !== null && !state.keyRejected && buildTranscriptRecords(lines, state.sessionKey, state.seen).records.length === 0;
348
+ var nothingLeftToUpload = (state) => state.sessionKey !== null && !state.keyRejected && state.unsettled === 0;
349
+ var uploadStalled = (before, after) => after.sessionKey !== null && !after.keyRejected && after.unsettled > 0 && after.seen.size === before.seen.size;
331
350
  var nextInterval = (previousMs, idle, baseMs, maxMs) => idle ? Math.min(previousMs * 2, maxMs) : baseMs;
332
351
  var startTranscriptSync = (opts) => {
333
352
  let warnedAboutRecipients = false;
@@ -354,32 +373,50 @@ var startTranscriptSync = (opts) => {
354
373
  const persisted = loadSessionKey(opts.sessionId, opts.storage?.sessionKeyDirectory);
355
374
  let state = persisted ? { ...createSyncState(), ...persisted } : createSyncState();
356
375
  sweepStaleSessionKeys(Date.now(), opts.storage?.sessionKeyDirectory);
376
+ let persistedKey = persisted?.sessionKey ?? null;
357
377
  let persistedUploaded = persisted?.keyUploaded ?? false;
378
+ const persistSessionKey = () => {
379
+ if (!state.sessionKey || state.sessionKey === persistedKey && state.keyUploaded === persistedUploaded) return;
380
+ persistedKey = state.sessionKey;
381
+ persistedUploaded = state.keyUploaded;
382
+ saveSessionKey(opts.sessionId, {
383
+ sessionKey: state.sessionKey,
384
+ wrappedKey: state.wrappedKey,
385
+ providerWrappedKey: state.providerWrappedKey,
386
+ providerKeyId: state.providerKeyId,
387
+ keyUploaded: state.keyUploaded
388
+ }, opts.storage?.sessionKeyDirectory);
389
+ };
358
390
  let running = true;
359
391
  let inFlight = false;
392
+ let stalled = false;
393
+ let catchingUp = false;
360
394
  const tick = async () => {
395
+ catchingUp = false;
361
396
  if (!running || inFlight || !(opts.enabled ? opts.enabled() : transcriptsEnabled())) return;
362
397
  inFlight = true;
363
398
  try {
364
- const before = state.sessionKey;
365
399
  const ending = opts.ending?.() === true;
400
+ if (state.keyRejected) {
401
+ if (ending) opts.onDrained?.();
402
+ return;
403
+ }
404
+ state = await withSessionKey(state, uploader);
405
+ if (!state.sessionKey) return;
406
+ persistSessionKey();
407
+ const previous = state;
366
408
  const modified = existsSync2(path) ? statSync2(path).mtimeMs : null;
367
409
  const source = opts.source ?? "claude";
368
410
  const read2 = opts.epoch ? linesSeenDuringEpoch(opts.epoch, path, source, Date.now()) : null;
369
411
  const lines = read2?.lines ?? normalizeTranscriptLines(readLines(path), source);
370
412
  state = await syncTick(lines, state, uploader, opts.sessionId, opts.machineId);
371
- if (state.sessionKey && (before !== state.sessionKey || state.keyUploaded !== persistedUploaded)) {
372
- persistedUploaded = state.keyUploaded;
373
- saveSessionKey(opts.sessionId, {
374
- sessionKey: state.sessionKey,
375
- wrappedKey: state.wrappedKey,
376
- providerWrappedKey: state.providerWrappedKey,
377
- providerKeyId: state.providerKeyId,
378
- keyUploaded: state.keyUploaded
379
- }, opts.storage?.sessionKeyDirectory);
380
- }
381
- if (opts.epoch && read2 && nothingLeftToUpload(state, lines)) recordSettledPosition(opts.epoch, path, read2.cutoff, read2.completeThroughOffset);
382
- if (ending && opts.ending?.() && existsSync2(path) && statSync2(path).mtimeMs === modified && state.keyUploaded && nothingLeftToUpload(state, lines)) opts.onDrained?.();
413
+ stalled = uploadStalled(previous, state);
414
+ persistSessionKey();
415
+ const settled = nothingLeftToUpload(state);
416
+ if (opts.epoch && read2 && settled) recordSettledPosition(opts.epoch, path, read2.cutoff, read2.completeThroughOffset);
417
+ catchingUp = settled && read2 !== null && !read2.reachedEnd && read2.completeThroughOffset > read2.cutoff.offset;
418
+ const readEverything = read2?.reachedEnd ?? true;
419
+ if (ending && opts.ending?.() && existsSync2(path) && statSync2(path).mtimeMs === modified && settled && readEverything) opts.onDrained?.();
383
420
  } catch {
384
421
  } finally {
385
422
  inFlight = false;
@@ -394,14 +431,14 @@ var startTranscriptSync = (opts) => {
394
431
  void (async () => {
395
432
  const before = state.sessionKey;
396
433
  await tick();
397
- const idle = state.sessionKey === null && before === null || state.keyUnavailable;
398
- schedule(nextInterval(delayMs, idle, baseIntervalMs, maxIntervalMs));
434
+ const waiting = state.sessionKey === null && before === null || state.keyUnavailable || state.keyRejected;
435
+ const ceilingMs = waiting ? maxIntervalMs : Math.min(maxIntervalMs, baseIntervalMs * STALLED_BACKOFF_FACTOR);
436
+ schedule(catchingUp ? CATCH_UP_DELAY_MS : nextInterval(Math.max(delayMs, baseIntervalMs), waiting || stalled, baseIntervalMs, ceilingMs));
399
437
  })();
400
438
  }, delayMs);
401
439
  if (typeof timer.unref === "function") timer.unref();
402
440
  };
403
- void tick();
404
- schedule(baseIntervalMs);
441
+ schedule(0);
405
442
  return () => {
406
443
  running = false;
407
444
  if (timer) clearTimeout(timer);