@skaile/workspaces 4.27.2 → 4.28.0

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 (139) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/app-sdk/index.js +1 -1
  3. package/dist/{asset-feeds-JOL4TGBX.js → asset-feeds-DRGVRBN5.js} +4 -4
  4. package/dist/{asset-feeds-JOL4TGBX.js.map → asset-feeds-DRGVRBN5.js.map} +1 -1
  5. package/dist/asset-manager/index.js +1 -1
  6. package/dist/bridge/drivers/claude-sdk.js +4 -4
  7. package/dist/bridge/drivers/codex.js +2 -2
  8. package/dist/bridge/drivers/continue.js +3 -3
  9. package/dist/bridge/drivers/echo.js +3 -3
  10. package/dist/bridge/drivers/gemini.js +5 -5
  11. package/dist/bridge/drivers/goose.js +3 -3
  12. package/dist/bridge/drivers/omp.js +4 -4
  13. package/dist/bridge/drivers/opencode.js +3 -3
  14. package/dist/bridge/drivers/qwen.js +5 -5
  15. package/dist/bridge/index.js +5 -5
  16. package/dist/{chunk-YOPE344M.js → chunk-2JANXYTJ.js} +2 -2
  17. package/dist/chunk-2JANXYTJ.js.map +1 -0
  18. package/dist/{chunk-QRHIWDAZ.js → chunk-2LJDCZLP.js} +3 -3
  19. package/dist/{chunk-QRHIWDAZ.js.map → chunk-2LJDCZLP.js.map} +1 -1
  20. package/dist/{chunk-SEPPLMBH.js → chunk-32POIALR.js} +2 -2
  21. package/dist/{chunk-SEPPLMBH.js.map → chunk-32POIALR.js.map} +1 -1
  22. package/dist/{chunk-X7VMTARF.js → chunk-36HJNHDN.js} +4 -4
  23. package/dist/{chunk-X7VMTARF.js.map → chunk-36HJNHDN.js.map} +1 -1
  24. package/dist/{chunk-KVWSBQNP.js → chunk-5UQNCPIP.js} +3 -3
  25. package/dist/{chunk-KVWSBQNP.js.map → chunk-5UQNCPIP.js.map} +1 -1
  26. package/dist/{chunk-GKE66NTN.js → chunk-6ZELKHAI.js} +3 -3
  27. package/dist/{chunk-GKE66NTN.js.map → chunk-6ZELKHAI.js.map} +1 -1
  28. package/dist/{chunk-GRBB4CQL.js → chunk-DJZRPPFJ.js} +2 -2
  29. package/dist/chunk-DJZRPPFJ.js.map +1 -0
  30. package/dist/{chunk-AVYBLJ3A.js → chunk-DMXEFYND.js} +3 -3
  31. package/dist/{chunk-AVYBLJ3A.js.map → chunk-DMXEFYND.js.map} +1 -1
  32. package/dist/{chunk-TRRFUVDJ.js → chunk-ERDK4ATM.js} +3 -3
  33. package/dist/{chunk-TRRFUVDJ.js.map → chunk-ERDK4ATM.js.map} +1 -1
  34. package/dist/{chunk-7JC4ZIXJ.js → chunk-G3VT2BCY.js} +241 -41
  35. package/dist/chunk-G3VT2BCY.js.map +1 -0
  36. package/dist/{chunk-IQID7X6P.js → chunk-H5EGBMZ5.js} +2 -2
  37. package/dist/{chunk-IQID7X6P.js.map → chunk-H5EGBMZ5.js.map} +1 -1
  38. package/dist/{chunk-CNFRXYYQ.js → chunk-HCHH6TPK.js} +3 -3
  39. package/dist/{chunk-CNFRXYYQ.js.map → chunk-HCHH6TPK.js.map} +1 -1
  40. package/dist/{chunk-F4ECQAN3.js → chunk-HFVK7FKK.js} +3 -3
  41. package/dist/{chunk-F4ECQAN3.js.map → chunk-HFVK7FKK.js.map} +1 -1
  42. package/dist/{chunk-ECRMVY7D.js → chunk-LCLEAHFX.js} +6 -6
  43. package/dist/{chunk-ECRMVY7D.js.map → chunk-LCLEAHFX.js.map} +1 -1
  44. package/dist/{chunk-NGNNL7YN.js → chunk-PL4LZ4OQ.js} +2 -2
  45. package/dist/{chunk-NGNNL7YN.js.map → chunk-PL4LZ4OQ.js.map} +1 -1
  46. package/dist/{chunk-BADVX5LG.js → chunk-Q2AOHZFF.js} +4 -4
  47. package/dist/{chunk-BADVX5LG.js.map → chunk-Q2AOHZFF.js.map} +1 -1
  48. package/dist/{chunk-PQRU6GD2.js → chunk-RISETQGB.js} +3 -3
  49. package/dist/{chunk-PQRU6GD2.js.map → chunk-RISETQGB.js.map} +1 -1
  50. package/dist/{chunk-ZZK6N6R2.js → chunk-V73R7GJC.js} +3 -3
  51. package/dist/{chunk-ZZK6N6R2.js.map → chunk-V73R7GJC.js.map} +1 -1
  52. package/dist/{chunk-HMUFI3L5.js → chunk-VSG3YPG4.js} +3 -3
  53. package/dist/{chunk-HMUFI3L5.js.map → chunk-VSG3YPG4.js.map} +1 -1
  54. package/dist/{chunk-YNUISPG3.js → chunk-WYDJPPUF.js} +6 -6
  55. package/dist/{chunk-YNUISPG3.js.map → chunk-WYDJPPUF.js.map} +1 -1
  56. package/dist/{chunk-NLUW3IJL.js → chunk-X5CW2HDM.js} +3 -3
  57. package/dist/{chunk-NLUW3IJL.js.map → chunk-X5CW2HDM.js.map} +1 -1
  58. package/dist/{chunk-LFYAU2H3.js → chunk-XEBSA7YU.js} +6 -6
  59. package/dist/{chunk-LFYAU2H3.js.map → chunk-XEBSA7YU.js.map} +1 -1
  60. package/dist/{chunk-HMUE4ZTX.js → chunk-ZQWC5WBF.js} +55 -39
  61. package/dist/chunk-ZQWC5WBF.js.map +1 -0
  62. package/dist/cli/index.js +36 -36
  63. package/dist/connectors/config.js +1 -1
  64. package/dist/connectors/index.js +8 -8
  65. package/dist/connectors/src/connector-base.d.ts +3 -3
  66. package/dist/connectors/src/connector-base.d.ts.map +1 -1
  67. package/dist/connectors/src/connector-manager.d.ts +1 -7
  68. package/dist/connectors/src/connector-manager.d.ts.map +1 -1
  69. package/dist/connectors/src/connector-types.d.ts +15 -3
  70. package/dist/connectors/src/connector-types.d.ts.map +1 -1
  71. package/dist/connectors/src/index.d.ts +1 -1
  72. package/dist/connectors/src/index.d.ts.map +1 -1
  73. package/dist/connectors-shared/index.js +2 -2
  74. package/dist/{ensure-sources-WQI2WQRY.js → ensure-sources-LLUFLA2F.js} +4 -4
  75. package/dist/{ensure-sources-WQI2WQRY.js.map → ensure-sources-LLUFLA2F.js.map} +1 -1
  76. package/dist/factory-assets/connectors/box.js +8 -8
  77. package/dist/factory-assets/connectors/deploy.js +8 -8
  78. package/dist/factory-assets/connectors/devserver.js +8 -8
  79. package/dist/factory-assets/connectors/flow/adapter.d.ts +17 -1
  80. package/dist/factory-assets/connectors/flow/adapter.d.ts.map +1 -1
  81. package/dist/factory-assets/connectors/flow/adapter.js +8 -8
  82. package/dist/factory-assets/connectors/flow/run-flow.js +9 -9
  83. package/dist/factory-assets/connectors/flow.js +8 -8
  84. package/dist/factory-assets/connectors/git/driver.d.ts +37 -2
  85. package/dist/factory-assets/connectors/git/driver.d.ts.map +1 -1
  86. package/dist/factory-assets/connectors/git.js +8 -8
  87. package/dist/factory-assets/connectors/gmail.js +8 -8
  88. package/dist/factory-assets/connectors/googledrive.js +8 -8
  89. package/dist/factory-assets/connectors/local.js +8 -8
  90. package/dist/factory-assets/connectors/mattermost.js +8 -8
  91. package/dist/factory-assets/connectors/memory.js +8 -8
  92. package/dist/factory-assets/connectors/minio.js +8 -8
  93. package/dist/factory-assets/connectors/postgres.js +8 -8
  94. package/dist/factory-assets/connectors/s3.js +8 -8
  95. package/dist/factory-assets/connectors/sharepoint.js +8 -8
  96. package/dist/factory-assets/connectors/sqlite.js +8 -8
  97. package/dist/factory-assets/connectors/static-server.js +8 -8
  98. package/dist/factory-assets/connectors/tunnel.js +8 -8
  99. package/dist/factory-assets/connectors/webdav.js +8 -8
  100. package/dist/factory-assets/connectors/xstate-store.js +8 -8
  101. package/dist/factory-assets/connectors/xstate.js +8 -8
  102. package/dist/{helpers-MJDVMQIE.js → helpers-KUI4C7BN.js} +4 -4
  103. package/dist/{helpers-MJDVMQIE.js.map → helpers-KUI4C7BN.js.map} +1 -1
  104. package/dist/{library-publish-XTS64S4P.js → library-publish-JURXXSXX.js} +6 -6
  105. package/dist/{library-publish-XTS64S4P.js.map → library-publish-JURXXSXX.js.map} +1 -1
  106. package/dist/{open-library-FSKAMF7C.js → open-library-B67SV3J5.js} +5 -5
  107. package/dist/{open-library-FSKAMF7C.js.map → open-library-B67SV3J5.js.map} +1 -1
  108. package/dist/{project-MGG4WTXD.js → project-DY7ZOBMA.js} +5 -5
  109. package/dist/{project-MGG4WTXD.js.map → project-DY7ZOBMA.js.map} +1 -1
  110. package/dist/runner/index.js +12 -12
  111. package/dist/runner/src/lifecycle-handler.d.ts.map +1 -1
  112. package/dist/runner/src/serve.d.ts +32 -5
  113. package/dist/runner/src/serve.d.ts.map +1 -1
  114. package/dist/sdk/asset-manager.js +1 -1
  115. package/dist/sdk/bridge.js +5 -5
  116. package/dist/sdk/index.js +12 -12
  117. package/dist/sdk/runner.js +12 -12
  118. package/dist/sdk/session.js +2 -2
  119. package/dist/sdk/types.js +1 -1
  120. package/dist/session/index.js +2 -2
  121. package/dist/{setup-XI5TL2W4.js → setup-YAHBP22C.js} +10 -10
  122. package/dist/{setup-XI5TL2W4.js.map → setup-YAHBP22C.js.map} +1 -1
  123. package/dist/{source-URUY7ZMP.js → source-LB6KXJQD.js} +6 -6
  124. package/dist/{source-URUY7ZMP.js.map → source-LB6KXJQD.js.map} +1 -1
  125. package/dist/{source-manifest-publish-Z4GN5MQ2.js → source-manifest-publish-O76QKC22.js} +7 -7
  126. package/dist/{source-manifest-publish-Z4GN5MQ2.js.map → source-manifest-publish-O76QKC22.js.map} +1 -1
  127. package/dist/tui/index.js +12 -12
  128. package/dist/types/index.js +1 -1
  129. package/dist/types/src/events.d.ts +45 -0
  130. package/dist/types/src/events.d.ts.map +1 -1
  131. package/dist/types/src/index.d.ts +1 -1
  132. package/dist/types/src/index.d.ts.map +1 -1
  133. package/dist/workspace-plugin/adapters/mcp.js +2 -2
  134. package/dist/workspace-plugin/index.js +1 -1
  135. package/package.json +1 -1
  136. package/dist/chunk-7JC4ZIXJ.js.map +0 -1
  137. package/dist/chunk-GRBB4CQL.js.map +0 -1
  138. package/dist/chunk-HMUE4ZTX.js.map +0 -1
  139. package/dist/chunk-YOPE344M.js.map +0 -1
@@ -1,17 +1,17 @@
1
- import { declaredConnectErrorKind, ClassifiedConnectError, withConnectErrorKind } from './chunk-KVWSBQNP.js';
2
- import { OAuthRequiredError, ConnectorFieldMissingError, LegacyAuthGrammarError, resolveAuthRef, readUnavailableMarker, ConnectorStartupError } from './chunk-YOPE344M.js';
3
- import { EventNormalizer } from './chunk-BADVX5LG.js';
4
- import { resolveModelTier } from './chunk-NLUW3IJL.js';
5
- import { createDriver } from './chunk-IQID7X6P.js';
1
+ import { declaredConnectErrorKind, ClassifiedConnectError, withConnectErrorKind } from './chunk-5UQNCPIP.js';
2
+ import { OAuthRequiredError, ConnectorFieldMissingError, LegacyAuthGrammarError, resolveAuthRef, readUnavailableMarker, ConnectorStartupError } from './chunk-2JANXYTJ.js';
3
+ import { EventNormalizer } from './chunk-Q2AOHZFF.js';
4
+ import { resolveModelTier } from './chunk-X5CW2HDM.js';
5
+ import { createDriver } from './chunk-H5EGBMZ5.js';
6
6
  import { pluginRegistry } from './chunk-6E6PKKAD.js';
7
7
  import { computeStimulus } from './chunk-IFGTRL2I.js';
8
8
  import { interpolateNodeInstruction, resolveNodeBindings, getConsumedOutputSchema, validateConsumedNodeOutput, appendAttempt, resolveTerminalFailureStatus, remainingActiveExecutionMs, deriveCheckEvidence, computeFlowStateFromSnapshots, availableRouterFrontier, evaluateRouterSelection, routerSelectionOutput, planRouterSkips, unsettledRouterBranchIds, countFailedAttempts, hasAutomaticRetryBudget, persistedRouterSelection } from './chunk-KTCMBEEB.js';
9
9
  import { INPUT_SCHEMA_SHAPES_HINT, coerceInputSchema } from './chunk-XPDB4O4H.js';
10
10
  import { parseFlowDefinition } from './chunk-ALLCAFHQ.js';
11
11
  import { describeStimulus, buildOrchestratorPrompt, renderSubpromptPrompt, renderStimulusPrompt } from './chunk-D6YOE2DB.js';
12
- import { deterministicNodeKindLabel, nodeInstruction, flowDefaults, isAgentNode, isGateNode, isCheckNode, nodeRequiresApproval, isSubFlowNode, isFunctionNode, isSubpromptNode, isRouterNode, isActiveRuntimeNode, nodeIsOptional, nodeLabel, nodeAssets } from './chunk-V4RGCKYC.js';
12
+ import { deterministicNodeKindLabel, nodeInstruction, flowDefaults, isAgentNode, isGateNode, isCheckNode, nodeRequiresApproval, isSubFlowNode, isActiveRuntimeNode, isFunctionNode, isSubpromptNode, isRouterNode, nodeIsOptional, nodeLabel, nodeAssets } from './chunk-V4RGCKYC.js';
13
13
  import { classifierDecision, withoutReservedClassifierFields } from './chunk-DHMBE5J7.js';
14
- import { withActivityLabelDefs } from './chunk-GRBB4CQL.js';
14
+ import { withActivityLabelDefs } from './chunk-DJZRPPFJ.js';
15
15
  import { processAlive } from './chunk-4GY63JU6.js';
16
16
  import { withFsDeadline, tryWithFsDeadline, FsDeadlineError, fsDeadlineMs } from './chunk-2FBPAR2V.js';
17
17
  import { portableSpawn } from './chunk-DPLIN2RA.js';
@@ -21,6 +21,7 @@ import { mkdir, rename, writeFile, readFile, stat, cp, rmdir, chmod, rm, readdir
21
21
  import * as z4 from 'zod';
22
22
  import { execFile } from 'child_process';
23
23
  import { promisify } from 'util';
24
+ import { tmpdir } from 'os';
24
25
  import { createReadStream, existsSync, mkdirSync, openSync, closeSync, chmodSync, utimesSync, readFileSync, writeSync, renameSync } from 'fs';
25
26
  import { createServer } from 'http';
26
27
  import mime from 'mime';
@@ -1549,6 +1550,10 @@ function gitPrefix(cwd) {
1549
1550
  return ["-c", `safe.directory=${cwd}`];
1550
1551
  }
1551
1552
  var SKAILE_INTERNAL_DIR = ".skaile";
1553
+ function isSkaileInternalPath(statusPath) {
1554
+ const p = statusPath.startsWith('"') ? statusPath.slice(1) : statusPath;
1555
+ return p === SKAILE_INTERNAL_DIR || p.startsWith(`${SKAILE_INTERNAL_DIR}/`);
1556
+ }
1552
1557
  var SKAILE_EXCLUDE_MARKER = "# skaile: platform-internal session state (git connector)";
1553
1558
  var UNSTAGE_BATCH = 500;
1554
1559
  async function commitIdentityArgs(cwd) {
@@ -1689,13 +1694,20 @@ async function ensureSkaileExcluded(cwd, log) {
1689
1694
  }
1690
1695
  }
1691
1696
  async function runGit(args, options) {
1692
- const { stdout } = await execFileAsync2("git", args, {
1697
+ const pending = execFileAsync2("git", args, {
1693
1698
  encoding: "utf-8",
1694
1699
  timeout: options.timeout,
1695
1700
  killSignal: "SIGKILL",
1696
1701
  ...options.cwd === void 0 ? {} : { cwd: options.cwd },
1697
- ...options.env === void 0 ? {} : { env: options.env }
1702
+ ...options.env === void 0 ? {} : { env: options.env },
1703
+ ...options.maxBuffer === void 0 ? {} : { maxBuffer: options.maxBuffer }
1698
1704
  });
1705
+ if (options.input !== void 0) {
1706
+ pending.child.stdin?.on("error", () => {
1707
+ });
1708
+ pending.child.stdin?.end(options.input);
1709
+ }
1710
+ const { stdout } = await pending;
1699
1711
  return stdout.trim();
1700
1712
  }
1701
1713
  function git(args, cwd, timeout = 3e4) {
@@ -1753,8 +1765,9 @@ async function runRemoteGit(args, auth, options) {
1753
1765
  );
1754
1766
  }
1755
1767
  const recursion = RECURSING_SUBCOMMANDS.has(subcommandOf(args)) ? NO_SUBMODULE_RECURSION : [];
1768
+ const cwd = options.cwd ?? options.neutralCwd;
1756
1769
  return runGit([...gitPrefix(options.safeDir), ...NETWORK_GIT_ARGS, ...recursion, ...args], {
1757
- ...options.cwd === void 0 ? {} : { cwd: options.cwd },
1770
+ ...cwd === void 0 ? {} : { cwd },
1758
1771
  timeout: options.timeout,
1759
1772
  env: networkGitEnv(withheld === null ? auth : void 0, options.env)
1760
1773
  });
@@ -1987,6 +2000,41 @@ async function gitOrNull(args, cwd) {
1987
2000
  return null;
1988
2001
  }
1989
2002
  }
2003
+ var PUSH_STATE_REMOTE_TIMEOUT_MS = 1e4;
2004
+ var PUSH_STATE_LOCAL_TIMEOUT_MS = 1e4;
2005
+ var PROBE_GIT_ARGS = [
2006
+ "-c",
2007
+ "core.fsmonitor=false",
2008
+ "-c",
2009
+ "status.showUntrackedFiles=all",
2010
+ "-c",
2011
+ "core.untrackedCache=false",
2012
+ "-c",
2013
+ "core.excludesFile=/dev/null"
2014
+ ];
2015
+ async function probeGitOrNull(args, cwd, input) {
2016
+ try {
2017
+ return await runGit([...gitPrefix(cwd), ...PROBE_GIT_ARGS, ...args], {
2018
+ cwd,
2019
+ timeout: PUSH_STATE_LOCAL_TIMEOUT_MS,
2020
+ env: { ...process.env, GIT_NO_REPLACE_OBJECTS: "1", GIT_WORK_TREE: cwd },
2021
+ maxBuffer: 64 * 1024 * 1024,
2022
+ ...input === void 0 ? {} : { input }
2023
+ });
2024
+ } catch {
2025
+ return null;
2026
+ }
2027
+ }
2028
+ async function hasInitialisedSubmodule(cwd) {
2029
+ const staged = await probeGitOrNull(["ls-files", "--stage", "-z"], cwd);
2030
+ if (staged === null) return true;
2031
+ for (const entry of staged.split("\0")) {
2032
+ if (!entry.startsWith("160000 ")) continue;
2033
+ const path = entry.slice(entry.indexOf(" ") + 1);
2034
+ if (await pathExists(join(cwd, path, ".git"))) return true;
2035
+ }
2036
+ return false;
2037
+ }
1990
2038
  async function countAheadBehind(cwd, remoteRef) {
1991
2039
  const out = await gitOrNull(["rev-list", "--left-right", "--count", `${remoteRef}...HEAD`], cwd);
1992
2040
  if (!out) {
@@ -2995,30 +3043,135 @@ var GitConnector = class extends AbstractConnector {
2995
3043
  };
2996
3044
  }
2997
3045
  // ── Session lifecycle ──────────────────────────────────────────────────────
3046
+ /**
3047
+ * Commit and push per the lifecycle config, then report what the checkout
3048
+ * can prove afterwards (`pushState`) so the host can tell whether anything
3049
+ * exists only on local disk. A push that throws still throws (no report).
3050
+ */
2998
3051
  async onHibernate(handle) {
2999
3052
  this.log.info("hibernate");
3000
3053
  const s = handle.state;
3001
3054
  if (s.fleetManaged) {
3002
3055
  return "fleet-managed";
3003
3056
  }
3004
- const lc = s.lifecycle;
3005
- if (!lc.commitOnHibernate) return;
3057
+ const cwd = handle.mountPath;
3006
3058
  return this.withMountLock(s, async () => {
3007
- const result = await commitAll(handle.mountPath, `skaile: hibernate snapshot`, this.log);
3008
- if (!result) return this.pushUnpushedOnHibernate(s, handle.mountPath);
3009
- const sha = await git(["rev-parse", "--short", "HEAD"], handle.mountPath);
3010
- if (lc.pushOnHibernate) {
3011
- try {
3012
- await this.pushActiveBranch(s, handle.mountPath);
3013
- this.log.info("push ok", { branch: s.activeBranch });
3014
- } catch (err) {
3015
- this.log.error("push failed", err, { branch: s.activeBranch });
3016
- throw err;
3017
- }
3018
- }
3019
- return `Committed ${sha} on ${s.activeBranch}${lc.pushOnHibernate ? " (pushed)" : ""}`;
3059
+ const detail = await this.hibernateSave(s, cwd);
3060
+ const pushState = await this.readPushState(s, cwd);
3061
+ return detail === void 0 ? { pushState } : { detail, pushState };
3020
3062
  });
3021
3063
  }
3064
+ /** The commit/push half of {@link onHibernate}; returns its detail line. Runs under the mount lock. */
3065
+ async hibernateSave(s, cwd) {
3066
+ const lc = s.lifecycle;
3067
+ if (!lc.commitOnHibernate) return void 0;
3068
+ const result = await commitAll(cwd, `skaile: hibernate snapshot`, this.log);
3069
+ if (!result) return this.pushUnpushedOnHibernate(s, cwd);
3070
+ const sha = await git(["rev-parse", "--short", "HEAD"], cwd);
3071
+ if (lc.pushOnHibernate) {
3072
+ try {
3073
+ await this.pushActiveBranch(s, cwd);
3074
+ this.log.info("push ok", { branch: s.activeBranch });
3075
+ } catch (err) {
3076
+ this.log.error("push failed", err, { branch: s.activeBranch });
3077
+ throw err;
3078
+ }
3079
+ }
3080
+ return `Committed ${sha} on ${s.activeBranch}${lc.pushOnHibernate ? " (pushed)" : ""}`;
3081
+ }
3082
+ /**
3083
+ * What this checkout can prove after a hibernate save, for a host deciding
3084
+ * whether deleting the workspace loses anything. Read-only: never fetches,
3085
+ * pushes, or writes the repo. Every doubt answers in the "keep it" direction.
3086
+ */
3087
+ async readPushState(s, cwd) {
3088
+ const status = await probeGitOrNull(
3089
+ ["status", "--porcelain", "--untracked-files=all", "--ignore-submodules=none"],
3090
+ cwd
3091
+ );
3092
+ const ignored = await probeGitOrNull(
3093
+ ["status", "--porcelain", "--ignored=matching", "--untracked-files=normal"],
3094
+ cwd
3095
+ );
3096
+ const head = await probeGitOrNull(["rev-parse", "--verify", "--quiet", "HEAD^{commit}"], cwd) || null;
3097
+ const abbrev = head === null ? null : await probeGitOrNull(["rev-parse", "--abbrev-ref", "HEAD"], cwd);
3098
+ return {
3099
+ clean: status === "",
3100
+ onRemote: await this.isWorkspaceOnRemote(s, cwd, head),
3101
+ ignoredFiles: ignored === null ? null : ignored.split("\n").some((line) => line.startsWith("!! ") && !isSkaileInternalPath(line.slice(3))),
3102
+ head,
3103
+ branch: abbrev === null || abbrev === "" || abbrev === "HEAD" ? null : abbrev
3104
+ };
3105
+ }
3106
+ /**
3107
+ * Whether every commit reachable from a local ref (`refs/heads/*`, `HEAD`
3108
+ * even when detached, `refs/stash`) is reachable from some remote branch
3109
+ * head. The remote heads come from `ls-remote`, because local `origin/*`
3110
+ * refs go stale (a push by URL does not move them); only the ones whose
3111
+ * commit this checkout already holds can be walked, so a head we lack
3112
+ * proves nothing and the answer leans to `false`.
3113
+ *
3114
+ * `false` for any initialised submodule, checked first: a commit pinned only
3115
+ * in its local clone is out of this walk's reach. `null` when the remote
3116
+ * cannot be asked within {@link PUSH_STATE_REMOTE_TIMEOUT_MS}, which includes
3117
+ * a remote the mount reaches only through ambient config (a credential helper,
3118
+ * ssh or CA settings in global/system gitconfig): that config is switched off
3119
+ * here, so such a workspace always reads "cannot tell" and is kept.
3120
+ */
3121
+ async isWorkspaceOnRemote(s, cwd, head) {
3122
+ if (await hasInitialisedSubmodule(cwd)) return false;
3123
+ let out;
3124
+ try {
3125
+ out = await runRemoteGit(["ls-remote", "--heads", plainRemoteUrl(s)], s, {
3126
+ neutralCwd: tmpdir(),
3127
+ safeDir: cwd,
3128
+ timeout: PUSH_STATE_REMOTE_TIMEOUT_MS,
3129
+ env: {
3130
+ ...process.env,
3131
+ GIT_CONFIG_GLOBAL: "/dev/null",
3132
+ GIT_CONFIG_NOSYSTEM: "1",
3133
+ GIT_NO_REPLACE_OBJECTS: "1"
3134
+ }
3135
+ });
3136
+ } catch (err) {
3137
+ this.log.warn("ls-remote for hibernate push state failed \u2014 cannot tell what is pushed", {
3138
+ error: redactCredentials(err instanceof Error ? err.message : String(err))
3139
+ });
3140
+ return null;
3141
+ }
3142
+ const refs = await probeGitOrNull(
3143
+ ["for-each-ref", "--format=%(objectname)", "refs/heads", "refs/tags", "refs/stash"],
3144
+ cwd
3145
+ );
3146
+ if (refs === null) return false;
3147
+ const local = new Set(refs.split("\n").filter((l) => l !== ""));
3148
+ if (head !== null) local.add(head);
3149
+ if (local.size === 0) return true;
3150
+ const remote = /* @__PURE__ */ new Set();
3151
+ for (const line of out.split("\n")) {
3152
+ const sha = line.split(" ")[0];
3153
+ if (sha) remote.add(sha);
3154
+ }
3155
+ let present = [];
3156
+ if (remote.size > 0) {
3157
+ const batch = await probeGitOrNull(
3158
+ ["cat-file", "--batch-check=%(objectname) %(objecttype)"],
3159
+ cwd,
3160
+ `${[...remote].join("\n")}
3161
+ `
3162
+ );
3163
+ if (batch === null) return false;
3164
+ present = batch.split("\n").map((line) => line.split(" ")).filter(([, type]) => type === "commit").map(([sha]) => sha);
3165
+ }
3166
+ const count = await probeGitOrNull(
3167
+ ["rev-list", "--count", "--stdin"],
3168
+ cwd,
3169
+ // `^<sha>` per line: older git does not honour `--not` on stdin.
3170
+ `${[...local, ...present.map((sha) => `^${sha}`)].join("\n")}
3171
+ `
3172
+ );
3173
+ return count === "0";
3174
+ }
3022
3175
  /**
3023
3176
  * Hibernate with nothing new to commit: push commits that are still only
3024
3177
  * local (the agent committed its own work, or an earlier push failed).
@@ -8424,8 +8577,17 @@ var ConnectorManager = class {
8424
8577
  continue;
8425
8578
  }
8426
8579
  try {
8427
- const detail = await fn.call(entry.connector, entry.handle);
8428
- results.push({ id, ok: true, detail: detail ?? void 0 });
8580
+ const outcome = await fn.call(entry.connector, entry.handle);
8581
+ if (outcome !== null && typeof outcome === "object") {
8582
+ results.push({
8583
+ id,
8584
+ ok: true,
8585
+ ...outcome.detail === void 0 ? {} : { detail: outcome.detail },
8586
+ ...outcome.pushState === void 0 ? {} : { pushState: outcome.pushState }
8587
+ });
8588
+ } else {
8589
+ results.push({ id, ok: true, detail: outcome ?? void 0 });
8590
+ }
8429
8591
  } catch (err) {
8430
8592
  results.push({
8431
8593
  id,
@@ -10169,7 +10331,8 @@ function prepareExecutionSnapshot(flowDef, execution) {
10169
10331
  const nodes = nodeExecutionRecord(Object.entries(snapshot.nodes ?? {}));
10170
10332
  for (const node of flowDef.nodes) {
10171
10333
  const existing = nodes[node.id];
10172
- if ((isSubFlowNode(node) || isSubpromptNode(node)) && existing && ["running", "awaiting_approval", "awaiting_input"].includes(existing.status)) {
10334
+ const interrupted = (isSubFlowNode(node) || isSubpromptNode(node)) && ["running", "awaiting_approval", "awaiting_input"].includes(existing?.status ?? "") || (isFunctionNode(node) || isCheckNode(node)) && existing?.status === "running";
10335
+ if (existing && interrupted) {
10173
10336
  nodes[node.id] = {
10174
10337
  ...existing,
10175
10338
  status: "not_started",
@@ -10240,6 +10403,7 @@ var FlowAdapter = class extends AbstractConnector {
10240
10403
  inlineSubFlowRunner: options.inlineSubFlowRunner,
10241
10404
  inlineOperationTargets: /* @__PURE__ */ new Map(),
10242
10405
  subpromptOperations: /* @__PURE__ */ new Map(),
10406
+ deterministicOperations: /* @__PURE__ */ new Map(),
10243
10407
  subpromptCleanup: /* @__PURE__ */ new Set(),
10244
10408
  flowInputOrigins: options.flowInputOrigins,
10245
10409
  inlineSubFlowAncestry: options.inlineSubFlowAncestry ?? [flowDef.id],
@@ -10254,7 +10418,7 @@ var FlowAdapter = class extends AbstractConnector {
10254
10418
  async disconnect(handle) {
10255
10419
  const state = this.s(handle);
10256
10420
  state.executionGeneration += 1;
10257
- await this.cancelSubprompts(state);
10421
+ await this.cancelRuntimeWork(state);
10258
10422
  this.clearWakeTimer(state);
10259
10423
  await this.cancelInlineTargets(state);
10260
10424
  handle.status = "disconnected";
@@ -10264,16 +10428,31 @@ var FlowAdapter = class extends AbstractConnector {
10264
10428
  s.inlineOperationTargets.clear();
10265
10429
  for (const target of targets) await target.cancel();
10266
10430
  }
10267
- async cancelSubprompts(s) {
10268
- for (const operation of s.subpromptOperations.values()) {
10269
- operation.controller.abort();
10270
- s.subpromptCleanup.add(operation.promise);
10271
- void operation.promise.then(
10272
- () => s.subpromptCleanup.delete(operation.promise),
10273
- () => s.subpromptCleanup.delete(operation.promise)
10431
+ /**
10432
+ * Abort in-flight subprompt and function/check work and join it, so a restored
10433
+ * run that re-runs the node never races the attempt it replaced. A
10434
+ * deterministic join is bounded: an executor may ignore its abort signal.
10435
+ */
10436
+ async cancelRuntimeWork(s) {
10437
+ const joins = [
10438
+ ...[...s.subpromptOperations.values()].map((operation) => {
10439
+ operation.controller.abort();
10440
+ return operation.promise;
10441
+ }),
10442
+ ...[...s.deterministicOperations.values()].map((operation) => {
10443
+ operation.controller.abort();
10444
+ return settleWithin(operation.promise, ABORTED_ATTEMPT_SETTLE_MS);
10445
+ })
10446
+ ];
10447
+ for (const join6 of joins) {
10448
+ s.subpromptCleanup.add(join6);
10449
+ void join6.then(
10450
+ () => s.subpromptCleanup.delete(join6),
10451
+ () => s.subpromptCleanup.delete(join6)
10274
10452
  );
10275
10453
  }
10276
10454
  s.subpromptOperations.clear();
10455
+ s.deterministicOperations.clear();
10277
10456
  await Promise.allSettled([...s.subpromptCleanup]);
10278
10457
  }
10279
10458
  projectInlineInteraction(handle, parentNodeId, projection2) {
@@ -10306,7 +10485,7 @@ var FlowAdapter = class extends AbstractConnector {
10306
10485
  */
10307
10486
  hydrate(handle, execution) {
10308
10487
  const s = this.s(handle);
10309
- void this.cancelSubprompts(s);
10488
+ void this.cancelRuntimeWork(s);
10310
10489
  assertLegal(
10311
10490
  s.inlineOperationTargets.size === 0,
10312
10491
  "hydrate requires live inline children to be cancelled first"
@@ -10814,7 +10993,7 @@ var FlowAdapter = class extends AbstractConnector {
10814
10993
  throw new Error("FlowAdapter: start requires args.seed.runId + args.seed.startedBy");
10815
10994
  }
10816
10995
  s.flowDef = flow;
10817
- void this.cancelSubprompts(s);
10996
+ void this.cancelRuntimeWork(s);
10818
10997
  s.executionGeneration += 1;
10819
10998
  s.execution = buildInitialExecution(flow, {
10820
10999
  runId: seed.runId,
@@ -11244,7 +11423,7 @@ var FlowAdapter = class extends AbstractConnector {
11244
11423
  */
11245
11424
  cancel(handle) {
11246
11425
  this.mutate(handle, (s) => {
11247
- void this.cancelSubprompts(s);
11426
+ void this.cancelRuntimeWork(s);
11248
11427
  s.execution = { ...s.execution, status: "cancelled" };
11249
11428
  s.executionGeneration += 1;
11250
11429
  return void 0;
@@ -11307,6 +11486,20 @@ var FlowAdapter = class extends AbstractConnector {
11307
11486
  }
11308
11487
  return false;
11309
11488
  }
11489
+ /**
11490
+ * Whether {@link drainRuntimeNodes} has a node to start: an `available` runtime-owned
11491
+ * node, or an inline sub-flow it would re-enter. A run restored from a snapshot is only
11492
+ * moved on by a turn kick, so the runner kicks one when this holds.
11493
+ */
11494
+ hasRuntimeWork(handle) {
11495
+ const { flowDef, execution } = this.s(handle);
11496
+ if (execution.status === "cancelled" || execution.status === "failed") return false;
11497
+ return flowDef.nodes.some((node) => {
11498
+ const status = execution.nodes[node.id]?.status;
11499
+ if (isSubFlowNode(node)) return status === "available" || status === "running";
11500
+ return !isAgentNode(node) && isActiveRuntimeNode(node) && status === "available";
11501
+ });
11502
+ }
11310
11503
  /**
11311
11504
  * Drain runtime-owned nodes in definition order until only agent work or a human decision
11312
11505
  * remains. Routers select branches, function nodes use NodeExecutor, gates park, and sub-flows
@@ -11703,6 +11896,10 @@ var FlowAdapter = class extends AbstractConnector {
11703
11896
  { node, inputs: resolved.values, inputOrigins: resolved.origins },
11704
11897
  { signal: deterministicAbort.signal }
11705
11898
  );
11899
+ state.deterministicOperations.set(node.id, {
11900
+ controller: deterministicAbort,
11901
+ promise: runPromise
11902
+ });
11706
11903
  const result = deterministicRemainingMs !== void 0 ? await raceWithTimeout(
11707
11904
  runPromise,
11708
11905
  Math.max(0, deterministicRemainingMs),
@@ -11762,6 +11959,9 @@ var FlowAdapter = class extends AbstractConnector {
11762
11959
  };
11763
11960
  }
11764
11961
  }
11962
+ if (state.deterministicOperations.get(node.id)?.controller === deterministicAbort) {
11963
+ state.deterministicOperations.delete(node.id);
11964
+ }
11765
11965
  if (this.s(handle).executionGeneration !== deterministicExecutionGeneration) {
11766
11966
  deterministicAbort.abort();
11767
11967
  break;
@@ -12580,5 +12780,5 @@ function describeFlowOperations() {
12580
12780
  }
12581
12781
 
12582
12782
  export { AbstractConnector, BUILTIN_CONNECTOR_CATALOG, BoxConnector, ClassifierSubpromptRunner, ConnectorManager, DeployConnector, DevServerConnector, FlowAdapter, GitConnector, GmailConnector, GoogleDriveConnector, LocalConnector, LogBuffer, MAX_REARM_MS, MIN_REFRESH_DELAY_MS, ManagedGitconfigCollisionError, MattermostConnector, MemoryConnector, MinIOConnector, NO_ACTIVE_FLOW_ERROR, PortPool, PostgresConnector, REFRESH_LEAD_MS, S3Connector, S3FetchStoppedError, S3PresignedRequestError, S3_PRESIGN_BATCH, SQLiteConnector, SessionInlineSubFlowRunner, SessionNodeExecutor, SessionSubpromptRunner, SharePointConnector, StaticServerConnector, TunnelConnector, WebDAVConnector, XStateConnector, XStateStoreConnector, __test, atomicReplaceCredential, buildConnectorPromptSection, buildConnectorToolDefs, buildFlowPromptEvent, buildFlowToolDefs, buildLazyFlowToolDefs, buildLazySdkFlowTools, buildSdkConnectorTools, buildSdkFlowTools, checkFleetMountLiveness, classifierQuestion, classifyConnectError, createConnector, createConnector10, createConnector11, createConnector12, createConnector13, createConnector14, createConnector15, createConnector16, createConnector17, createConnector18, createConnector19, createConnector2, createConnector20, createConnector3, createConnector4, createConnector5, createConnector6, createConnector7, createConnector8, createConnector9, createFsWatcher, createWorktree, defaultSpawn, describeFlowOperations, driveOrchestratorTurn, ensureDirMode, ensureFleetMounted, ensureRefreshAttemptStamp, findGitRoot, findMissingPackages, getConnector, installNpmPackages, isFleetManaged, isPackageResolvable, listConnectors, listWorktrees, missingTokenMediatorMessage, parseListObjectsV2, presignScopePrefix, presignableKey, readGitSyncStatus, registerBuiltinConnectors, removeMountBlock, removeUnavailableMountBlock, renderCredentialHelperScript, tryGetConnector, worktreeRegistry, writeHelperScript, writeMountBlock, writeUnavailableMountBlock };
12583
- //# sourceMappingURL=chunk-7JC4ZIXJ.js.map
12584
- //# sourceMappingURL=chunk-7JC4ZIXJ.js.map
12783
+ //# sourceMappingURL=chunk-G3VT2BCY.js.map
12784
+ //# sourceMappingURL=chunk-G3VT2BCY.js.map