@schoolai/shipyard 3.5.0-rc.20260504.0 → 3.5.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 (52) hide show
  1. package/dist/{auth-LS3NBD42.js → auth-SS7LV5XK.js} +4 -3
  2. package/dist/{chunk-GLH3V7NG.js → chunk-2J3WSIAF.js} +5 -3
  3. package/dist/{chunk-GLH3V7NG.js.map → chunk-2J3WSIAF.js.map} +1 -1
  4. package/dist/{chunk-YUG27SAR.js → chunk-2UN5AR7V.js} +2 -2
  5. package/dist/{chunk-ODCN6W33.js → chunk-3CAEALVL.js} +7 -5
  6. package/dist/{chunk-ODCN6W33.js.map → chunk-3CAEALVL.js.map} +1 -1
  7. package/dist/chunk-3MNPDCO5.js +1011 -0
  8. package/dist/chunk-3MNPDCO5.js.map +1 -0
  9. package/dist/{chunk-JQ7HCEFS.js → chunk-BNEE7ZPW.js} +8 -6
  10. package/dist/{chunk-JQ7HCEFS.js.map → chunk-BNEE7ZPW.js.map} +1 -1
  11. package/dist/{chunk-5LIPEC7P.js → chunk-GIFN3IPT.js} +4 -4
  12. package/dist/{chunk-3TB4VNFG.js → chunk-IISLTKYY.js} +2 -2
  13. package/dist/chunk-PI77CUEP.js +49 -0
  14. package/dist/chunk-PI77CUEP.js.map +1 -0
  15. package/dist/chunk-SNYEQHUK.js +64 -0
  16. package/dist/chunk-SNYEQHUK.js.map +1 -0
  17. package/dist/{chunk-XXTIKBCU.js → chunk-VBPHGPBR.js} +2 -2
  18. package/dist/{chunk-M5M6VC5F.js → chunk-VPMN47TL.js} +31 -72
  19. package/dist/chunk-VPMN47TL.js.map +1 -0
  20. package/dist/{git-repo-CNIKBYPB.js → git-repo-364VANDM.js} +5 -4
  21. package/dist/index.js +9 -8
  22. package/dist/index.js.map +1 -1
  23. package/dist/{logger-7XW3I4XN.js → logger-GQCSLSZH.js} +4 -3
  24. package/dist/{login-RHZDNC74.js → login-D6USDG5M.js} +7 -6
  25. package/dist/{logout-CUAAF5IK.js → logout-VUNCW5B2.js} +6 -5
  26. package/dist/{logout-CUAAF5IK.js.map → logout-VUNCW5B2.js.map} +1 -1
  27. package/dist/mcp-servers-FZV2P2ZO.js +16 -0
  28. package/dist/{roi-LN7MMRH7.js → roi-Y3MX5UW4.js} +4 -3
  29. package/dist/{roi-LN7MMRH7.js.map → roi-Y3MX5UW4.js.map} +1 -1
  30. package/dist/{serve-E7CHPJD4.js → serve-IVUGCBEE.js} +73 -462
  31. package/dist/{serve-E7CHPJD4.js.map → serve-IVUGCBEE.js.map} +1 -1
  32. package/dist/services/watcher-worker/worker.d.ts +49 -0
  33. package/dist/services/watcher-worker/worker.js +157 -0
  34. package/dist/services/watcher-worker/worker.js.map +1 -0
  35. package/dist/{skills-OMDIMU7D.js → skills-GPGRNV4R.js} +2 -2
  36. package/dist/start-I7ZONWK7.js +285 -0
  37. package/dist/start-I7ZONWK7.js.map +1 -0
  38. package/package.json +1 -1
  39. package/dist/chunk-M5M6VC5F.js.map +0 -1
  40. package/dist/mcp-servers-3SHS2PEJ.js +0 -15
  41. package/dist/start-HQ42GOYF.js +0 -36
  42. package/dist/start-HQ42GOYF.js.map +0 -1
  43. /package/dist/{auth-LS3NBD42.js.map → auth-SS7LV5XK.js.map} +0 -0
  44. /package/dist/{chunk-YUG27SAR.js.map → chunk-2UN5AR7V.js.map} +0 -0
  45. /package/dist/{chunk-5LIPEC7P.js.map → chunk-GIFN3IPT.js.map} +0 -0
  46. /package/dist/{chunk-3TB4VNFG.js.map → chunk-IISLTKYY.js.map} +0 -0
  47. /package/dist/{chunk-XXTIKBCU.js.map → chunk-VBPHGPBR.js.map} +0 -0
  48. /package/dist/{git-repo-CNIKBYPB.js.map → git-repo-364VANDM.js.map} +0 -0
  49. /package/dist/{logger-7XW3I4XN.js.map → logger-GQCSLSZH.js.map} +0 -0
  50. /package/dist/{login-RHZDNC74.js.map → login-D6USDG5M.js.map} +0 -0
  51. /package/dist/{mcp-servers-3SHS2PEJ.js.map → mcp-servers-FZV2P2ZO.js.map} +0 -0
  52. /package/dist/{skills-OMDIMU7D.js.map → skills-GPGRNV4R.js.map} +0 -0
@@ -1,4 +1,20 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ addWorktreeToCache,
4
+ detectEnvironments,
5
+ findProjectRoot,
6
+ getGitTopLevel,
7
+ getRepoDefaultBranch,
8
+ getRepoMetadata,
9
+ isAncestor,
10
+ isCorruptionError,
11
+ isEexist,
12
+ isEnoent,
13
+ isGhAvailable,
14
+ isGitRepo,
15
+ parseOwnerRepo,
16
+ removeWorktreeFromCache
17
+ } from "./chunk-BNEE7ZPW.js";
2
18
  import {
3
19
  DiscoveryStateSchema,
4
20
  detectMCPServers,
@@ -9,10 +25,16 @@ import {
9
25
  redactEnv,
10
26
  resolveEnabledMcpServers,
11
27
  resolveStdioEnv
12
- } from "./chunk-5LIPEC7P.js";
28
+ } from "./chunk-GIFN3IPT.js";
13
29
  import {
14
30
  detectSkills
15
- } from "./chunk-XXTIKBCU.js";
31
+ } from "./chunk-VBPHGPBR.js";
32
+ import {
33
+ configureFileWatcherGuard,
34
+ createMetricsCollector,
35
+ guardedSubscribe,
36
+ shutdownFileWatcherGuard
37
+ } from "./chunk-3MNPDCO5.js";
16
38
  import {
17
39
  TRAILER_SCHEMA_VERSION,
18
40
  appendTrailerToMessage,
@@ -26,6 +48,9 @@ import {
26
48
  import {
27
49
  getRecentWasmPanicMessages
28
50
  } from "./chunk-7H34LI75.js";
51
+ import {
52
+ assertNever
53
+ } from "./chunk-SNYEQHUK.js";
29
54
  import {
30
55
  AuthGitHubCallbackRequestSchema,
31
56
  AuthGitHubCallbackResponseSchema,
@@ -72,37 +97,23 @@ import {
72
97
  classifyClaudeCodeCompatibility
73
98
  } from "./chunk-6TYNQ5KQ.js";
74
99
  import "./chunk-EHQITHQX.js";
75
- import {
76
- loadAuthToken
77
- } from "./chunk-GLH3V7NG.js";
78
- import {
79
- addWorktreeToCache,
80
- detectEnvironments,
81
- findProjectRoot,
82
- getGitTopLevel,
83
- getRepoDefaultBranch,
84
- getRepoMetadata,
85
- isAncestor,
86
- isCorruptionError,
87
- isEexist,
88
- isEnoent,
89
- isGhAvailable,
90
- isGitRepo,
91
- parseOwnerRepo,
92
- removeWorktreeFromCache
93
- } from "./chunk-JQ7HCEFS.js";
94
100
  import {
95
101
  createChildLogger,
96
102
  flushLogger,
97
103
  logger
98
- } from "./chunk-YUG27SAR.js";
104
+ } from "./chunk-2UN5AR7V.js";
105
+ import {
106
+ loadAuthToken
107
+ } from "./chunk-2J3WSIAF.js";
99
108
  import {
100
- external_exports,
101
109
  getShipyardHome,
102
110
  isVanillaAgentMode,
103
- toJSONSchema,
104
111
  validateEnv
105
- } from "./chunk-M5M6VC5F.js";
112
+ } from "./chunk-PI77CUEP.js";
113
+ import {
114
+ external_exports,
115
+ toJSONSchema
116
+ } from "./chunk-VPMN47TL.js";
106
117
  import {
107
118
  AUTH_STATUS_TIMEOUT_MS,
108
119
  BUFFER_OVERFLOW_MSG,
@@ -33510,371 +33521,6 @@ var FileStorageAdapter = class _FileStorageAdapter extends StorageAdapter {
33510
33521
  }
33511
33522
  };
33512
33523
 
33513
- // src/shared/assert-never.ts
33514
- function assertNever(value) {
33515
- throw new Error(`Unexpected value: ${JSON.stringify(value)}`);
33516
- }
33517
-
33518
- // src/shared/file-watcher-guard.ts
33519
- var DEFAULT_MAX_ACTIVE_WATCHERS = 450;
33520
- var ENV_MAX = process.env.SHIPYARD_FILE_WATCHER_MAX;
33521
- var PARSED_ENV_MAX = ENV_MAX ? Number.parseInt(ENV_MAX, 10) : Number.NaN;
33522
- var MAX_ACTIVE_WATCHERS = Number.isFinite(PARSED_ENV_MAX) && PARSED_ENV_MAX > 0 ? PARSED_ENV_MAX : DEFAULT_MAX_ACTIVE_WATCHERS;
33523
- var STARTING_BACKOFF_MS_INITIAL = 250;
33524
- var STARTING_BACKOFF_MS_ESCALATION = 1e3;
33525
- var MAX_BACKOFF_MS = 3e4;
33526
- var BACKOFF_RESET_AFTER_MS = 5 * 6e4;
33527
- var CIRCUIT_FAILURES = 5;
33528
- var CIRCUIT_WINDOW_MS = 6e4;
33529
- var CIRCUIT_OPEN_MS = 5 * 6e4;
33530
- var CIRCUIT_OPEN_MAX_MS = 30 * 6e4;
33531
- var ESSENTIAL_RESUBSCRIBE_DELAY_MS = 1e3;
33532
- function makeInitialAttemptState() {
33533
- return {
33534
- failureCount: 0,
33535
- backoffMs: 0,
33536
- lastFailureAt: 0,
33537
- circuitOpenedAt: null,
33538
- circuitCooldownMs: CIRCUIT_OPEN_MS,
33539
- recentFailures: [],
33540
- halfOpenAt: null
33541
- };
33542
- }
33543
- function isCleanAttemptState(state) {
33544
- return state.circuitOpenedAt === null && state.failureCount === 0 && state.backoffMs === 0 && state.recentFailures.length === 0 && state.halfOpenAt === null;
33545
- }
33546
- function decideAction(state, event, now) {
33547
- switch (event.kind) {
33548
- case "request_subscribe":
33549
- return decideRequest(state, event, now);
33550
- case "subscribe_success":
33551
- return decideSuccess(state, now);
33552
- case "subscribe_failure":
33553
- return decideFailure(state, now);
33554
- default:
33555
- return assertNever(event);
33556
- }
33557
- }
33558
- function decideRequest(state, event, now) {
33559
- const decayed = decayBackoff(state, now);
33560
- if (decayed.circuitOpenedAt !== null) {
33561
- const cooldownEnd = decayed.circuitOpenedAt + decayed.circuitCooldownMs;
33562
- if (now < cooldownEnd) {
33563
- return {
33564
- state: decayed,
33565
- action: { kind: "reject_stub", reason: "circuit_open" },
33566
- signals: []
33567
- };
33568
- }
33569
- return {
33570
- state: { ...decayed, halfOpenAt: now },
33571
- action: event.activeCount >= MAX_ACTIVE_WATCHERS ? { kind: "evict_and_subscribe" } : { kind: "subscribe" },
33572
- signals: [{ kind: "circuit_probe" }]
33573
- };
33574
- }
33575
- if (decayed.backoffMs > 0 && now < decayed.lastFailureAt + decayed.backoffMs) {
33576
- const remaining = decayed.lastFailureAt + decayed.backoffMs - now;
33577
- return { state: decayed, action: { kind: "wait", ms: remaining }, signals: [] };
33578
- }
33579
- let nextState = decayed;
33580
- if (decayed.backoffMs === 0 && event.reason === "escalation") {
33581
- nextState = { ...decayed, backoffMs: STARTING_BACKOFF_MS_ESCALATION };
33582
- }
33583
- if (event.activeCount >= MAX_ACTIVE_WATCHERS) {
33584
- return { state: nextState, action: { kind: "evict_and_subscribe" }, signals: [] };
33585
- }
33586
- return { state: nextState, action: { kind: "subscribe" }, signals: [] };
33587
- }
33588
- function decideSuccess(state, _now) {
33589
- const wasHalfOpen = state.halfOpenAt !== null;
33590
- const next = {
33591
- failureCount: 0,
33592
- backoffMs: 0,
33593
- lastFailureAt: 0,
33594
- circuitOpenedAt: null,
33595
- circuitCooldownMs: CIRCUIT_OPEN_MS,
33596
- recentFailures: [],
33597
- halfOpenAt: null
33598
- };
33599
- return {
33600
- state: next,
33601
- action: { kind: "noop" },
33602
- signals: wasHalfOpen ? [{ kind: "circuit_closed" }] : []
33603
- };
33604
- }
33605
- function decideFailure(state, now) {
33606
- const recent = [...state.recentFailures.filter((t) => now - t < CIRCUIT_WINDOW_MS), now];
33607
- const baseBackoff = state.backoffMs === 0 ? STARTING_BACKOFF_MS_INITIAL : Math.min(state.backoffMs * 2, MAX_BACKOFF_MS);
33608
- if (state.halfOpenAt !== null) {
33609
- const nextCooldown = Math.min(state.circuitCooldownMs * 2, CIRCUIT_OPEN_MAX_MS);
33610
- return {
33611
- state: {
33612
- ...state,
33613
- failureCount: state.failureCount + 1,
33614
- backoffMs: baseBackoff,
33615
- lastFailureAt: now,
33616
- recentFailures: recent,
33617
- circuitOpenedAt: now,
33618
- circuitCooldownMs: nextCooldown,
33619
- halfOpenAt: null
33620
- },
33621
- action: { kind: "noop" },
33622
- signals: [{ kind: "circuit_opened" }]
33623
- };
33624
- }
33625
- if (recent.length >= CIRCUIT_FAILURES && state.circuitOpenedAt === null) {
33626
- return {
33627
- state: {
33628
- ...state,
33629
- failureCount: state.failureCount + 1,
33630
- backoffMs: baseBackoff,
33631
- lastFailureAt: now,
33632
- recentFailures: recent,
33633
- circuitOpenedAt: now,
33634
- circuitCooldownMs: CIRCUIT_OPEN_MS,
33635
- halfOpenAt: null
33636
- },
33637
- action: { kind: "noop" },
33638
- signals: [{ kind: "circuit_opened" }]
33639
- };
33640
- }
33641
- return {
33642
- state: {
33643
- ...state,
33644
- failureCount: state.failureCount + 1,
33645
- backoffMs: baseBackoff,
33646
- lastFailureAt: now,
33647
- recentFailures: recent
33648
- },
33649
- action: { kind: "noop" },
33650
- signals: []
33651
- };
33652
- }
33653
- function decayBackoff(state, now) {
33654
- if (state.lastFailureAt === 0 || state.backoffMs === 0) return state;
33655
- const sinceLast = now - state.lastFailureAt;
33656
- if (sinceLast >= BACKOFF_RESET_AFTER_MS) {
33657
- return { ...state, backoffMs: 0, failureCount: 0, recentFailures: [] };
33658
- }
33659
- const halvings = Math.floor(sinceLast / 6e4);
33660
- if (halvings === 0) return state;
33661
- const next = Math.max(STARTING_BACKOFF_MS_INITIAL, state.backoffMs >> halvings);
33662
- return { ...state, backoffMs: next };
33663
- }
33664
- var moduleState = makeModuleState();
33665
- function makeModuleState() {
33666
- return {
33667
- active: /* @__PURE__ */ new Set(),
33668
- reservations: /* @__PURE__ */ new Set(),
33669
- perPath: /* @__PURE__ */ new Map(),
33670
- /** Cache of circuit-open log emission so we log only once per opening. */
33671
- loggedOpenAt: /* @__PURE__ */ new Map(),
33672
- /** Live deps; overridden in tests via _resetGuardForTesting / configureFileWatcherGuard. */
33673
- deps: defaultDeps()
33674
- };
33675
- }
33676
- function defaultDeps() {
33677
- return {
33678
- subscribe: async (path2, fn, opts) => {
33679
- const mod = await import("@parcel/watcher");
33680
- return mod.subscribe(path2, fn, opts);
33681
- },
33682
- log: () => {
33683
- },
33684
- now: () => Date.now(),
33685
- setTimeout: (fn, ms) => setTimeout(fn, ms)
33686
- };
33687
- }
33688
- function occupancy() {
33689
- return moduleState.active.size + moduleState.reservations.size;
33690
- }
33691
- function configureFileWatcherGuard(deps) {
33692
- moduleState.deps = { ...moduleState.deps, log: deps.log };
33693
- }
33694
- async function guardedSubscribe(path2, callback, opts, tier, reason) {
33695
- const { deps } = moduleState;
33696
- const now = deps.now();
33697
- const priorState = moduleState.perPath.get(path2) ?? makeInitialAttemptState();
33698
- const decision = decideAction(
33699
- priorState,
33700
- { kind: "request_subscribe", reason, activeCount: occupancy() },
33701
- now
33702
- );
33703
- moduleState.perPath.set(path2, decision.state);
33704
- emitSignals(path2, decision.signals);
33705
- switch (decision.action.kind) {
33706
- case "reject_stub":
33707
- return makeStubSubscription();
33708
- case "wait": {
33709
- const waitMs = decision.action.ms;
33710
- await new Promise((resolve5) => deps.setTimeout(() => resolve5(), waitMs));
33711
- return guardedSubscribe(path2, callback, opts, tier, "escalation");
33712
- }
33713
- case "evict_and_subscribe":
33714
- evictOne(path2);
33715
- return performSubscribe(path2, callback, opts, tier);
33716
- case "subscribe":
33717
- return performSubscribe(path2, callback, opts, tier);
33718
- case "noop":
33719
- throw new Error("guardedSubscribe: unexpected noop on request");
33720
- default:
33721
- return assertNever(decision.action);
33722
- }
33723
- }
33724
- async function performSubscribe(path2, consumerCallback, opts, tier) {
33725
- const { deps } = moduleState;
33726
- let entry = null;
33727
- const reservation = { path: path2, tier, reservedAt: deps.now() };
33728
- moduleState.reservations.add(reservation);
33729
- const wrapped = (err, events) => {
33730
- if (entry) entry.lastUsedAt = deps.now();
33731
- consumerCallback(err, events);
33732
- };
33733
- try {
33734
- const sub = await deps.subscribe(path2, wrapped, opts);
33735
- moduleState.reservations.delete(reservation);
33736
- const now = deps.now();
33737
- const priorState = moduleState.perPath.get(path2) ?? makeInitialAttemptState();
33738
- const successDecision = decideAction(priorState, { kind: "subscribe_success" }, now);
33739
- if (isCleanAttemptState(successDecision.state)) {
33740
- moduleState.perPath.delete(path2);
33741
- } else {
33742
- moduleState.perPath.set(path2, successDecision.state);
33743
- }
33744
- emitSignals(path2, successDecision.signals);
33745
- entry = {
33746
- path: path2,
33747
- tier,
33748
- lastUsedAt: now,
33749
- unsubscribe: () => sub.unsubscribe(),
33750
- consumerCallback
33751
- };
33752
- moduleState.active.add(entry);
33753
- deps.log({ event: "file_watcher_active_count", count: moduleState.active.size });
33754
- return {
33755
- unsubscribe: async () => {
33756
- if (entry && moduleState.active.has(entry)) {
33757
- moduleState.active.delete(entry);
33758
- }
33759
- const current2 = moduleState.perPath.get(path2);
33760
- if (current2 && isCleanAttemptState(current2)) {
33761
- moduleState.perPath.delete(path2);
33762
- }
33763
- await sub.unsubscribe();
33764
- }
33765
- };
33766
- } catch (err) {
33767
- moduleState.reservations.delete(reservation);
33768
- const now = deps.now();
33769
- const priorState = moduleState.perPath.get(path2) ?? makeInitialAttemptState();
33770
- const failureDecision = decideAction(priorState, { kind: "subscribe_failure" }, now);
33771
- moduleState.perPath.set(path2, failureDecision.state);
33772
- deps.log({
33773
- event: "file_watcher_subscribe_failed",
33774
- path: path2,
33775
- err: err instanceof Error ? err.message : String(err)
33776
- });
33777
- emitSignals(path2, failureDecision.signals);
33778
- if (failureDecision.state.circuitOpenedAt !== null) {
33779
- return makeStubSubscription();
33780
- }
33781
- throw err;
33782
- }
33783
- }
33784
- function pickOldest(entries, tier) {
33785
- let target = null;
33786
- for (const entry of entries) {
33787
- if (tier !== null && entry.tier !== tier) continue;
33788
- if (target === null || entry.lastUsedAt < target.lastUsedAt) target = entry;
33789
- }
33790
- return target;
33791
- }
33792
- function selectEvictionVictim(entries) {
33793
- const lazy = pickOldest(entries, "lazy");
33794
- if (lazy !== null) return { victim: lazy, evictingEssential: false };
33795
- const any = pickOldest(entries, null);
33796
- if (any !== null) return { victim: any, evictingEssential: true };
33797
- return null;
33798
- }
33799
- function evictOne(incomingPath) {
33800
- const { deps } = moduleState;
33801
- if (moduleState.active.size === 0) {
33802
- throw new Error("file-watcher-guard: cannot evict \u2014 active set is empty (counter is broken)");
33803
- }
33804
- const selection = selectEvictionVictim(moduleState.active);
33805
- if (selection === null) {
33806
- throw new Error("file-watcher-guard: eviction selection failed");
33807
- }
33808
- const { victim, evictingEssential } = selection;
33809
- moduleState.active.delete(victim);
33810
- deps.log({
33811
- event: evictingEssential ? "file_watcher_essential_evicted" : "file_watcher_evicted",
33812
- path: victim.path,
33813
- tier: victim.tier,
33814
- incomingPath
33815
- });
33816
- queueMicrotask(() => {
33817
- victim.consumerCallback(null, [{ type: "evicted", path: victim.path }]);
33818
- });
33819
- victim.unsubscribe().catch((err) => {
33820
- deps.log({
33821
- event: "file_watcher_unsubscribe_failed_during_eviction",
33822
- path: victim.path,
33823
- err: err instanceof Error ? err.message : String(err)
33824
- });
33825
- });
33826
- if (evictingEssential) {
33827
- scheduleEssentialResubscribe(victim);
33828
- }
33829
- }
33830
- function scheduleEssentialResubscribe(victim) {
33831
- const { deps } = moduleState;
33832
- deps.log({
33833
- event: "file_watcher_essential_re_subscribe_scheduled",
33834
- path: victim.path,
33835
- delayMs: ESSENTIAL_RESUBSCRIBE_DELAY_MS
33836
- });
33837
- deps.setTimeout(() => {
33838
- void retryEssentialSubscribe(victim);
33839
- }, ESSENTIAL_RESUBSCRIBE_DELAY_MS);
33840
- }
33841
- async function retryEssentialSubscribe(victim) {
33842
- const { deps } = moduleState;
33843
- try {
33844
- await guardedSubscribe(victim.path, victim.consumerCallback, {}, "essential", "rescan");
33845
- deps.log({ event: "file_watcher_essential_re_subscribed", path: victim.path });
33846
- } catch (err) {
33847
- deps.log({
33848
- event: "file_watcher_essential_re_subscribe_failed",
33849
- path: victim.path,
33850
- err: err instanceof Error ? err.message : String(err)
33851
- });
33852
- }
33853
- }
33854
- function emitSignals(path2, signals) {
33855
- const { deps } = moduleState;
33856
- for (const sig of signals) {
33857
- switch (sig.kind) {
33858
- case "circuit_opened":
33859
- deps.log({ event: "file_watcher_circuit_open", path: path2 });
33860
- moduleState.loggedOpenAt.set(path2, deps.now());
33861
- break;
33862
- case "circuit_closed":
33863
- deps.log({ event: "file_watcher_circuit_closed", path: path2 });
33864
- moduleState.loggedOpenAt.delete(path2);
33865
- break;
33866
- case "circuit_probe":
33867
- break;
33868
- default:
33869
- assertNever(sig);
33870
- }
33871
- }
33872
- }
33873
- function makeStubSubscription() {
33874
- return { unsubscribe: async () => {
33875
- } };
33876
- }
33877
-
33878
33524
  // src/shared/log-instruments.ts
33879
33525
  function logChannelSent(log, channel, opts) {
33880
33526
  const msgId = opts?.msgId ?? crypto.randomUUID();
@@ -34770,6 +34416,20 @@ var LifecycleManager = class {
34770
34416
  const intHandler = () => void this.#shutdown("SIGINT");
34771
34417
  process.on("SIGTERM", termHandler);
34772
34418
  process.on("SIGINT", intHandler);
34419
+ const isForkedChild = typeof process.send === "function";
34420
+ const isShutdownMessage = (msg) => {
34421
+ if (msg === null || typeof msg !== "object") return false;
34422
+ const cmd = Reflect.get(msg, "cmd");
34423
+ return cmd === "shutdown";
34424
+ };
34425
+ const messageHandler = (msg) => {
34426
+ if (isShutdownMessage(msg)) {
34427
+ void this.#shutdown("ipc-shutdown");
34428
+ }
34429
+ };
34430
+ if (isForkedChild) {
34431
+ process.on("message", messageHandler);
34432
+ }
34773
34433
  const exceptionHandler = (error2) => {
34774
34434
  const severity = classifyUncaughtError(error2);
34775
34435
  if (severity === "recoverable") {
@@ -34809,6 +34469,9 @@ var LifecycleManager = class {
34809
34469
  () => process.removeListener("unhandledRejection", rejectionHandler),
34810
34470
  () => process.removeListener("exit", exitHandler)
34811
34471
  ];
34472
+ if (isForkedChild) {
34473
+ this.#cleanupFns.push(() => process.removeListener("message", messageHandler));
34474
+ }
34812
34475
  void getSupportedEfforts().catch(() => void 0);
34813
34476
  }
34814
34477
  destroy() {
@@ -43030,10 +42693,10 @@ function friendlyExecError(err) {
43030
42693
  async function refreshPluginCapabilities(daemon, tokenStore) {
43031
42694
  const [updatedMarketplace, updatedMcp, updatedSkills] = await Promise.all([
43032
42695
  detectMarketplacePlugins(),
43033
- import("./mcp-servers-3SHS2PEJ.js").then(
42696
+ import("./mcp-servers-FZV2P2ZO.js").then(
43034
42697
  (m2) => m2.detectMCPServers(daemon.capabilities.environments, tokenStore)
43035
42698
  ),
43036
- import("./skills-OMDIMU7D.js").then(
42699
+ import("./skills-GPGRNV4R.js").then(
43037
42700
  (m2) => m2.detectSkills(daemon.capabilities.environments)
43038
42701
  )
43039
42702
  ]);
@@ -49153,72 +48816,6 @@ async function setupLocalDirect(deps) {
49153
48816
  };
49154
48817
  }
49155
48818
 
49156
- // src/services/metrics/metrics-collector.ts
49157
- var NOOP_METRICS = {
49158
- capture() {
49159
- },
49160
- dispose() {
49161
- }
49162
- };
49163
- var MetricsCollector = class {
49164
- #workerUrl;
49165
- #authToken;
49166
- #maxBatchSize;
49167
- #buffer = [];
49168
- #timer = null;
49169
- #disposed = false;
49170
- constructor(workerUrl, authToken, opts) {
49171
- this.#workerUrl = workerUrl.replace(/\/$/, "");
49172
- this.#authToken = authToken;
49173
- this.#maxBatchSize = opts?.maxBatchSize ?? 50;
49174
- const intervalMs = opts?.flushIntervalMs ?? 3e4;
49175
- this.#timer = setInterval(() => {
49176
- this.flush();
49177
- }, intervalMs);
49178
- this.#timer.unref();
49179
- }
49180
- capture(eventType, properties) {
49181
- if (this.#disposed) return;
49182
- const taskId = typeof properties?.taskId === "string" ? properties.taskId : void 0;
49183
- this.#buffer.push({
49184
- eventType,
49185
- taskId,
49186
- payload: properties ?? {},
49187
- clientTimestamp: Date.now()
49188
- });
49189
- if (this.#buffer.length >= this.#maxBatchSize) {
49190
- this.flush();
49191
- }
49192
- }
49193
- flush() {
49194
- if (this.#buffer.length === 0) return;
49195
- const events = this.#buffer;
49196
- this.#buffer = [];
49197
- const body = { events };
49198
- fetch(`${this.#workerUrl}/ingest`, {
49199
- method: "POST",
49200
- headers: {
49201
- "Content-Type": "application/json",
49202
- Authorization: `Bearer ${this.#authToken}`
49203
- },
49204
- body: JSON.stringify(body)
49205
- }).catch(() => {
49206
- });
49207
- }
49208
- dispose() {
49209
- this.#disposed = true;
49210
- if (this.#timer) {
49211
- clearInterval(this.#timer);
49212
- this.#timer = null;
49213
- }
49214
- this.flush();
49215
- }
49216
- };
49217
- function createMetricsCollector(workerUrl, authToken, telemetryEnabled) {
49218
- if (!telemetryEnabled || !workerUrl || !authToken) return NOOP_METRICS;
49219
- return new MetricsCollector(workerUrl, authToken);
49220
- }
49221
-
49222
48819
  // src/services/plugins/plugin-event-bus.ts
49223
48820
  var MAX_HANDLERS_PER_PLUGIN = 32;
49224
48821
  var PluginEventBus = class {
@@ -121956,7 +121553,7 @@ async function createDaemon(deps) {
121956
121553
  if (!cwd) return null;
121957
121554
  try {
121958
121555
  const { run: run4 } = await import("./shell-JINTQUIR.js");
121959
- const { getRepoDefaultBranch: getRepoDefaultBranch2 } = await import("./git-repo-CNIKBYPB.js");
121556
+ const { getRepoDefaultBranch: getRepoDefaultBranch2 } = await import("./git-repo-364VANDM.js");
121960
121557
  const branch = (await run4("git", ["rev-parse", "--abbrev-ref", "HEAD"], cwd)).trim();
121961
121558
  if (!branch || branch === "HEAD") return null;
121962
121559
  const pr = branchPrStateCache.get(taskId)?.currentBranchPR;
@@ -124426,7 +124023,12 @@ async function serve(options = {}) {
124426
124023
  "file_watcher_subscribe_failed",
124427
124024
  "file_watcher_active_count",
124428
124025
  "file_watcher_essential_re_subscribed",
124429
- "file_watcher_essential_re_subscribe_failed"
124026
+ "file_watcher_essential_re_subscribe_failed",
124027
+ /** Watcher worker supervisor (Commit 2): restart-class telemetry. */
124028
+ "watcher_worker_started",
124029
+ "watcher_worker_died",
124030
+ "watcher_worker_circuit_open",
124031
+ "watcher_worker_circuit_closed"
124430
124032
  ]);
124431
124033
  configureFileWatcherGuard({
124432
124034
  log: (entry) => {
@@ -124435,7 +124037,8 @@ async function serve(options = {}) {
124435
124037
  const { event, ...payload } = entry;
124436
124038
  metricsCollector.capture(event, payload);
124437
124039
  }
124438
- }
124040
+ },
124041
+ metrics: metricsCollector
124439
124042
  });
124440
124043
  const sessionServerUrl = new URL(resolvedSignalingUrl).origin;
124441
124044
  const detectedPortsRef = {
@@ -124981,6 +124584,14 @@ async function serve(options = {}) {
124981
124584
  fileWatcherPool.dispose().catch((err) => {
124982
124585
  log.warn({ event: "shutdown_step_failed", step: "file_watcher_pool", err: String(err) });
124983
124586
  }),
124587
+ /** Watcher worker supervisor: cooperative shutdown then SIGTERM/SIGKILL escalation. */
124588
+ shutdownFileWatcherGuard().catch((err) => {
124589
+ log.warn({
124590
+ event: "shutdown_step_failed",
124591
+ step: "file_watcher_supervisor",
124592
+ err: String(err)
124593
+ });
124594
+ }),
124984
124595
  collabRoomManager?.destroy().catch((err) => {
124985
124596
  log.warn({
124986
124597
  event: "shutdown_step_failed",
@@ -125018,4 +124629,4 @@ export {
125018
124629
  decideWorkspaceScope,
125019
124630
  serve
125020
124631
  };
125021
- //# sourceMappingURL=serve-E7CHPJD4.js.map
124632
+ //# sourceMappingURL=serve-IVUGCBEE.js.map