@livx.cc/agentx 0.99.47 → 0.99.49

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.
@@ -1,4 +1,4 @@
1
- import { A as AgentTool } from './tools-BqL8Lk4J.js';
1
+ import { k as JobRegistry, A as AgentTool } from './tools-HsbxgqjF.js';
2
2
  import '@livx.cc/wcli/core';
3
3
 
4
4
  /**
@@ -81,7 +81,7 @@ interface ShellJobConfig {
81
81
  spawn?: SpawnFn;
82
82
  env?: Record<string, string>;
83
83
  redactEnv?: boolean;
84
- /** Tail buffer cap per job (bytes); older output is dropped. Default 256 KB. */
84
+ /** Tail buffer cap per job (bytes); older output is dropped. Default 256 KB. Ignored when `jobs` is shared. */
85
85
  maxBuffer?: number;
86
86
  /** Kill all jobs on process exit (the CLI sets this; tests leave it off to avoid global handlers). */
87
87
  killOnExit?: boolean;
@@ -92,8 +92,15 @@ interface ShellJobConfig {
92
92
  * that finishes has to reach the MODEL, or `background:true` is a write-only hole — the model starts
93
93
  * a job, forgets it, and never collects the result. The host wires this to `agent.inject(...)`, which
94
94
  * folds the notice in at the next step boundary (and re-opens the turn if the model was about to stop).
95
+ * A job REAPED as stuck is reported too (status `killed` + `reason`).
95
96
  */
96
97
  onExit?: JobExitHandler;
98
+ /** The generic job registry these jobs live in. Share the Agent's (`AgentOptions.jobs`) so one
99
+ * JobStatus/JobOutput surface and one liveness reaper cover shell, MCP and delegated tools alike. */
100
+ jobs?: JobRegistry;
101
+ /** Cumulative CPU seconds of a process group — the "is a silent job still working?" probe used before an
102
+ * ADOPTED job is reaped as idle. Default: `ps` (psGroupCpuSeconds); return undefined when unknown. */
103
+ cpuTime?: (pgid: number) => Promise<number | undefined>;
97
104
  }
98
105
  interface JobExitNotice {
99
106
  id: string;
@@ -101,24 +108,43 @@ interface JobExitNotice {
101
108
  status: JobStatus;
102
109
  exitCode?: number;
103
110
  tail: string;
111
+ reason?: string;
104
112
  }
105
113
  type JobExitHandler = (n: JobExitNotice) => void;
106
114
  /** The exact text a completion notice becomes. Shared so every host (CLI, presets, embedders) pushes the
107
115
  * same thing back to the model instead of each inventing its own wording. */
108
116
  declare function formatJobExit(n: JobExitNotice): string;
117
+ /** Parse `ps` TIME (`[[dd-]hh:]mm:ss[.cc]`) to seconds. */
118
+ declare function parsePsTime(t: string): number | undefined;
119
+ /** Summed CPU seconds of the job's live processes: its process group (`pgid` = the detached leader's pid) PLUS every
120
+ * descendant of that pid — a child that moved to its own group (`timeout`, `setsid`, some build tools) still works for
121
+ * the job and must count. One `ps` call, C locale (stable number format); macOS + Linux. Undefined when nothing is
122
+ * left or ps is unavailable — the reaper then treats CPU as unknown and does NOT kill on it. */
123
+ declare function psGroupCpuSeconds(pgid: number): Promise<number | undefined>;
124
+ /** Pure part of `psGroupCpuSeconds`: parse `pid ppid pgid time` rows, sum the group ∪ descendants of `root`. */
125
+ declare function sumTreeCpu(psOut: string, root: number): number | undefined;
109
126
  /**
110
- * Per-session registry of background `/bin/sh` jobs. Backs `Shell({background:true})` and the
111
- * `ShellOutput`/`ShellStatus`/`ShellKill` tools. Output accumulates into a tail-capped ring so a
112
- * chatty process can't OOM. Bounded + killable; the CLI wires `killOnExit` so children are reaped.
127
+ * Per-session registry of background `/bin/sh` jobs. Backs `Shell({background:true})`, foreground-deadline
128
+ * adoption, and the `ShellOutput`/`ShellStatus`/`ShellKill` tools. A thin OS layer over the generic
129
+ * `JobRegistry` (src/tools.jobs.ts): output ring, liveness, notices and the stuck-job reaper live there.
130
+ *
131
+ * Liveness policy: an EXPLICIT `background:true` job is never idle-reaped (a quiet dev server is healthy).
132
+ * An ADOPTED job (a foreground command that outran its timeout) is: after the `shell` idle window with no
133
+ * output AND no CPU progress across its process group, it is SIGTERMed (SIGKILL after the grace period)
134
+ * and reported as `killed: stuck: idle Ns`.
113
135
  */
114
136
  declare class ShellJobRegistry {
115
137
  private cfg;
116
- private jobs;
117
- private seq;
138
+ readonly jobs: JobRegistry;
139
+ private meta;
118
140
  constructor(cfg: ShellJobConfig);
119
141
  start(command: string): Promise<string>;
120
- /** Fire `onExit` at most once per job, with the tail so the model can act without a second round-trip. */
121
- private notified;
142
+ private track;
143
+ private attach;
144
+ /** SIGTERM the whole group (bg children are detached group leaders — /bin/sh alone would orphan a forked
145
+ * server), then SIGKILL after the grace period if it is still there. Falls back to the pid for fakes. */
146
+ private signal;
147
+ /** Fire `onExit` at most once per job (the registry guarantees one terminal state), with the tail so the model can act without a second round-trip. */
122
148
  private notifyExit;
123
149
  /**
124
150
  * Wire (or rewire) the completion callback AFTER construction. A host that only gets its agent handle
@@ -135,6 +161,7 @@ declare class ShellJobRegistry {
135
161
  status: JobStatus;
136
162
  exitCode?: number;
137
163
  bytes: number;
164
+ reason?: string;
138
165
  } | null;
139
166
  list(): Array<{
140
167
  id: string;
@@ -147,9 +174,11 @@ declare class ShellJobRegistry {
147
174
  * worse, a launcher that spawned its own detached worker leaves that worker running with nothing
148
175
  * tracking it. Adopting hands the model a handle instead: the command keeps going, its completion
149
176
  * is reported like any other job, and `seed` carries the output produced before the handoff.
177
+ * Unlike an explicit background job it IS liveness-checked (idle window + CPU probe): nobody asked for
178
+ * a long-lived process here, so one that goes silent and CPU-idle is stuck, not serving.
150
179
  */
151
180
  adopt(command: string, proc: SpawnedProcess, seed?: string): string;
152
- kill(id: string): boolean;
181
+ kill(id: string, reason?: string): boolean;
153
182
  killAll(): void;
154
183
  }
155
184
  /** Build an opt-in real-shell tool bound to `options.cwd`. */
@@ -161,4 +190,4 @@ declare function makeRealShellTool(options: RealShellOptions): AgentTool;
161
190
  * job (its registry is dropped), so it must not be able to inspect or SIGTERM the parent's either. */
162
191
  declare function makeShellJobTools(registry: ShellJobRegistry): AgentTool[];
163
192
 
164
- export { type JobExitHandler, type JobExitNotice, type JobStatus, type RealShellOptions, type ShellJobConfig, ShellJobRegistry, type SpawnFn, type SpawnedProcess, formatJobExit, makeRealShellTool, makeShellJobTools };
193
+ export { type JobExitHandler, type JobExitNotice, type JobStatus, type RealShellOptions, type ShellJobConfig, ShellJobRegistry, type SpawnFn, type SpawnedProcess, formatJobExit, makeRealShellTool, makeShellJobTools, parsePsTime, psGroupCpuSeconds, sumTreeCpu };