@rynx-ai/runtime 0.1.11-beta.23 → 0.1.11-beta.24
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.
- package/dist/claude/executor.d.ts +19 -5
- package/dist/claude/executor.js +56 -12
- package/dist/host.js +109 -24
- package/dist/runner/manager.d.ts +1 -0
- package/dist/runner/manager.js +13 -0
- package/package.json +2 -2
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
import type { SkillMeta } from "@rynx-ai/core";
|
|
2
|
+
export interface MaterializedClaudePlugin {
|
|
3
|
+
pluginDir: string;
|
|
4
|
+
}
|
|
5
|
+
/** Stable Claude `--plugin-dir` owned by one Rynx Session. */
|
|
6
|
+
export declare function claudePluginDir(sessionId: string): string;
|
|
2
7
|
/**
|
|
3
|
-
*
|
|
8
|
+
* Return the existing Session-owned plugin directory as-is. It is the durable
|
|
9
|
+
* Provider input for this Session, not an immutable shared cache: runtime files
|
|
10
|
+
* created inside it (for example Python `__pycache__`) remain part of that
|
|
11
|
+
* Session and do not trigger SkillRef replay.
|
|
12
|
+
*/
|
|
13
|
+
export declare function reuseClaudePlugin(sessionId: string): Promise<MaterializedClaudePlugin | null>;
|
|
14
|
+
/**
|
|
15
|
+
* Materialize a selected catalog skill subset into a Session-owned Claude
|
|
4
16
|
* `--plugin-dir` (a dir with `skills/<name>/SKILL.md` + a `.claude-plugin/plugin.json`
|
|
5
17
|
* manifest — claude's mechanism for exposing skills outside its host dirs, since
|
|
6
18
|
* it doesn't scan `~/.rynx/skills`). Consumed by the claude-native live launch.
|
|
7
19
|
*
|
|
20
|
+
* The committed path is deterministic and survives Provider/runner restarts.
|
|
21
|
+
* An existing directory is returned as-is. The first materialization is built
|
|
22
|
+
* in a sibling staging directory and renamed into the stable path so a crash
|
|
23
|
+
* cannot expose a partially copied plugin.
|
|
24
|
+
*
|
|
8
25
|
* Returns `null` when there's nothing to add. Rynx-managed Claude sessions load
|
|
9
26
|
* no host/project/local setting sources, so this explicit plugin directory is
|
|
10
27
|
* the only native skill channel; the selected subset is enforced exactly.
|
|
11
28
|
*/
|
|
12
|
-
export declare function
|
|
13
|
-
pluginDir?: string;
|
|
14
|
-
cleanup?: () => Promise<void>;
|
|
15
|
-
} | null>;
|
|
29
|
+
export declare function materializeClaudePlugin(sessionId: string, selected: SkillMeta[] | null | undefined): Promise<MaterializedClaudePlugin | null>;
|
package/dist/claude/executor.js
CHANGED
|
@@ -1,26 +1,70 @@
|
|
|
1
|
-
import { cp, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
1
|
+
import { cp, mkdir, mkdtemp, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
3
2
|
import path from "node:path";
|
|
3
|
+
import { runtimeSessionStateDir } from "../runtime-state-paths.js";
|
|
4
|
+
/** Stable Claude `--plugin-dir` owned by one Rynx Session. */
|
|
5
|
+
export function claudePluginDir(sessionId) {
|
|
6
|
+
return path.join(runtimeSessionStateDir(sessionId), "claude-plugin");
|
|
7
|
+
}
|
|
4
8
|
/**
|
|
5
|
-
*
|
|
9
|
+
* Return the existing Session-owned plugin directory as-is. It is the durable
|
|
10
|
+
* Provider input for this Session, not an immutable shared cache: runtime files
|
|
11
|
+
* created inside it (for example Python `__pycache__`) remain part of that
|
|
12
|
+
* Session and do not trigger SkillRef replay.
|
|
13
|
+
*/
|
|
14
|
+
export async function reuseClaudePlugin(sessionId) {
|
|
15
|
+
const pluginDir = claudePluginDir(sessionId);
|
|
16
|
+
try {
|
|
17
|
+
return (await stat(pluginDir)).isDirectory() ? { pluginDir } : null;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Materialize a selected catalog skill subset into a Session-owned Claude
|
|
6
25
|
* `--plugin-dir` (a dir with `skills/<name>/SKILL.md` + a `.claude-plugin/plugin.json`
|
|
7
26
|
* manifest — claude's mechanism for exposing skills outside its host dirs, since
|
|
8
27
|
* it doesn't scan `~/.rynx/skills`). Consumed by the claude-native live launch.
|
|
9
28
|
*
|
|
29
|
+
* The committed path is deterministic and survives Provider/runner restarts.
|
|
30
|
+
* An existing directory is returned as-is. The first materialization is built
|
|
31
|
+
* in a sibling staging directory and renamed into the stable path so a crash
|
|
32
|
+
* cannot expose a partially copied plugin.
|
|
33
|
+
*
|
|
10
34
|
* Returns `null` when there's nothing to add. Rynx-managed Claude sessions load
|
|
11
35
|
* no host/project/local setting sources, so this explicit plugin directory is
|
|
12
36
|
* the only native skill channel; the selected subset is enforced exactly.
|
|
13
37
|
*/
|
|
14
|
-
export async function
|
|
38
|
+
export async function materializeClaudePlugin(sessionId, selected) {
|
|
15
39
|
if (selected == null || selected.length === 0)
|
|
16
40
|
return null;
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
41
|
+
const reused = await reuseClaudePlugin(sessionId);
|
|
42
|
+
if (reused)
|
|
43
|
+
return reused;
|
|
44
|
+
const pluginDir = claudePluginDir(sessionId);
|
|
45
|
+
const stateDir = runtimeSessionStateDir(sessionId);
|
|
46
|
+
await mkdir(stateDir, { recursive: true, mode: 0o700 });
|
|
47
|
+
const stagingDir = await mkdtemp(path.join(stateDir, ".claude-plugin-stage-"));
|
|
48
|
+
try {
|
|
49
|
+
const skillsRoot = path.join(stagingDir, "skills");
|
|
50
|
+
await mkdir(skillsRoot, { recursive: true });
|
|
51
|
+
for (const skill of selected) {
|
|
52
|
+
await cp(skill.dir, path.join(skillsRoot, skill.name), { recursive: true });
|
|
53
|
+
}
|
|
54
|
+
await mkdir(path.join(stagingDir, ".claude-plugin"), { recursive: true });
|
|
55
|
+
await writeFile(path.join(stagingDir, ".claude-plugin", "plugin.json"), `${JSON.stringify({ name: "rynx-agent-skills", description: "Per-agent skill subset" }, null, 2)}\n`);
|
|
56
|
+
try {
|
|
57
|
+
await rename(stagingDir, pluginDir);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
const concurrent = await reuseClaudePlugin(sessionId);
|
|
61
|
+
if (!concurrent)
|
|
62
|
+
throw error;
|
|
63
|
+
return concurrent;
|
|
64
|
+
}
|
|
65
|
+
return { pluginDir };
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
await rm(stagingDir, { recursive: true, force: true });
|
|
22
69
|
}
|
|
23
|
-
await mkdir(path.join(dir, ".claude-plugin"), { recursive: true });
|
|
24
|
-
await writeFile(path.join(dir, ".claude-plugin", "plugin.json"), `${JSON.stringify({ name: "rynx-agent-skills", description: "Per-agent skill subset" }, null, 2)}\n`);
|
|
25
|
-
return { pluginDir: dir, cleanup: () => rm(dir, { recursive: true, force: true }) };
|
|
26
70
|
}
|
package/dist/host.js
CHANGED
|
@@ -9,7 +9,7 @@ import { getRuntimeProfile, } from "@rynx-ai/core";
|
|
|
9
9
|
import { resolveRuntimeBinary, } from "@rynx-ai/core";
|
|
10
10
|
import { createCodexChildEnv } from "./codex-child-env.js";
|
|
11
11
|
import { prepareRuntimeHome, populateCodexSkills, runtimeHomePath, } from "./codex-home.js";
|
|
12
|
-
import {
|
|
12
|
+
import { materializeClaudePlugin, reuseClaudePlugin, } from "./claude/executor.js";
|
|
13
13
|
import { listClaudeModels } from "./claude/models.js";
|
|
14
14
|
import { CodexAppServerClient, buildRuntimeUserInput, } from "./codex-app-server/client.js";
|
|
15
15
|
import { buildAppServerBaseArgs, CodexTransportError, } from "./codex-app-server/transport.js";
|
|
@@ -529,16 +529,21 @@ export class LocalAgentHost {
|
|
|
529
529
|
return sameSessionSnapshots(existingClaude.workspace, existingClaude.execution, snapshotOpts);
|
|
530
530
|
}
|
|
531
531
|
// Dedupe concurrent triggers so only one forwarder is ever created per
|
|
532
|
-
// session (two would double-mirror every turn).
|
|
533
|
-
//
|
|
534
|
-
//
|
|
535
|
-
// the thread id instead of launching a bare `codex --remote` pane.
|
|
532
|
+
// session (two would double-mirror every turn). startLiveCodexSession
|
|
533
|
+
// publishes its partially initialized session before thread/start completes,
|
|
534
|
+
// so wait for that startup and then adopt any newer mutable Turn settings.
|
|
536
535
|
const inflight = this.liveEnsuring.get(localThreadId);
|
|
537
|
-
if (inflight)
|
|
538
|
-
|
|
536
|
+
if (inflight) {
|
|
537
|
+
if (!await inflight)
|
|
538
|
+
return false;
|
|
539
|
+
const startedLive = this.liveSessions.get(localThreadId);
|
|
540
|
+
return startedLive
|
|
541
|
+
? updateLiveCodexTurnSettings(startedLive, snapshotOpts)
|
|
542
|
+
: false;
|
|
543
|
+
}
|
|
539
544
|
const live = this.liveSessions.get(localThreadId);
|
|
540
545
|
if (live)
|
|
541
|
-
return
|
|
546
|
+
return updateLiveCodexTurnSettings(live, snapshotOpts);
|
|
542
547
|
const started = this.startLiveCodexSession(localThreadId, emit, snapshotOpts);
|
|
543
548
|
this.liveEnsuring.set(localThreadId, started);
|
|
544
549
|
try {
|
|
@@ -670,6 +675,8 @@ export class LocalAgentHost {
|
|
|
670
675
|
approvalPolicy,
|
|
671
676
|
model,
|
|
672
677
|
reasoningEffort,
|
|
678
|
+
appliedModel: model,
|
|
679
|
+
appliedReasoningEffort: reasoningEffort,
|
|
673
680
|
...(execution.instructions ? { instructions: execution.instructions } : {}),
|
|
674
681
|
threadId: record?.codexSessionId ?? null,
|
|
675
682
|
ready,
|
|
@@ -681,6 +688,8 @@ export class LocalAgentHost {
|
|
|
681
688
|
injectLock: Promise.resolve(),
|
|
682
689
|
pendingInjectedInputs: [],
|
|
683
690
|
publishInjectedInput: () => undefined,
|
|
691
|
+
publishTurnAdmission: () => undefined,
|
|
692
|
+
publishTurnAdmissionFailure: () => undefined,
|
|
684
693
|
publishInterrupted: () => undefined,
|
|
685
694
|
interruptedResponseId: null,
|
|
686
695
|
subscribing: false,
|
|
@@ -737,6 +746,21 @@ export class LocalAgentHost {
|
|
|
737
746
|
for (const se of n.userInput(content))
|
|
738
747
|
emitCurrent(se);
|
|
739
748
|
};
|
|
749
|
+
live.publishTurnAdmission = () => {
|
|
750
|
+
emitCurrent({
|
|
751
|
+
type: "session.status",
|
|
752
|
+
sessionId: currentSessionId,
|
|
753
|
+
status: "running",
|
|
754
|
+
});
|
|
755
|
+
};
|
|
756
|
+
live.publishTurnAdmissionFailure = (message) => {
|
|
757
|
+
emitCurrent({
|
|
758
|
+
type: "session.status",
|
|
759
|
+
sessionId: currentSessionId,
|
|
760
|
+
status: "failed",
|
|
761
|
+
note: message,
|
|
762
|
+
});
|
|
763
|
+
};
|
|
740
764
|
const clearPendingInputsForResponse = (responseId) => {
|
|
741
765
|
if (!responseId)
|
|
742
766
|
return;
|
|
@@ -1389,6 +1413,13 @@ export class LocalAgentHost {
|
|
|
1389
1413
|
};
|
|
1390
1414
|
live.pendingInjectedInputs.push(pendingInput);
|
|
1391
1415
|
let injectionMethod = "turn/start";
|
|
1416
|
+
let admissionPublished = false;
|
|
1417
|
+
const publishAdmission = () => {
|
|
1418
|
+
if (admissionPublished)
|
|
1419
|
+
return;
|
|
1420
|
+
admissionPublished = true;
|
|
1421
|
+
live.publishTurnAdmission();
|
|
1422
|
+
};
|
|
1392
1423
|
const forgetPendingInput = () => {
|
|
1393
1424
|
const index = live.pendingInjectedInputs.indexOf(pendingInput);
|
|
1394
1425
|
if (index >= 0)
|
|
@@ -1396,6 +1427,12 @@ export class LocalAgentHost {
|
|
|
1396
1427
|
};
|
|
1397
1428
|
const injectionClient = this.injectionClientFactory(live.appServerUrl);
|
|
1398
1429
|
try {
|
|
1430
|
+
// Omnigent publishes codex-native running only after the native Terminal
|
|
1431
|
+
// is ready and the runner has accepted the message, but before the
|
|
1432
|
+
// short-lived app-server client initializes and starts the Turn. Claude
|
|
1433
|
+
// deliberately has no matching synthesized edge.
|
|
1434
|
+
if (!live.forwarder.isTurnOpen())
|
|
1435
|
+
publishAdmission();
|
|
1399
1436
|
await injectionClient.ensureInitialized();
|
|
1400
1437
|
// Match Omnigent's executor: each message uses one initialized client
|
|
1401
1438
|
// that closes as soon as turn/start or turn/steer is acknowledged.
|
|
@@ -1419,15 +1456,34 @@ export class LocalAgentHost {
|
|
|
1419
1456
|
return { outcome: "steered", responseId: `resp_codex_${steered.turnId}` };
|
|
1420
1457
|
}
|
|
1421
1458
|
}
|
|
1422
|
-
//
|
|
1423
|
-
//
|
|
1459
|
+
// Match Omnigent's turn boundary: change the native thread settings
|
|
1460
|
+
// under the same lock immediately before starting the next Turn. Never
|
|
1461
|
+
// put settings on turn/start or mutate a Turn that is already open.
|
|
1462
|
+
const desiredModel = live.model;
|
|
1463
|
+
const desiredReasoningEffort = live.reasoningEffort;
|
|
1464
|
+
const settings = {
|
|
1465
|
+
threadId,
|
|
1466
|
+
...(desiredModel !== live.appliedModel
|
|
1467
|
+
? { model: desiredModel || null }
|
|
1468
|
+
: {}),
|
|
1469
|
+
...(desiredReasoningEffort !== live.appliedReasoningEffort
|
|
1470
|
+
? { effort: desiredReasoningEffort ?? null }
|
|
1471
|
+
: {}),
|
|
1472
|
+
};
|
|
1473
|
+
if (Object.keys(settings).length > 1) {
|
|
1474
|
+
await injectionClient.threadSettingsUpdate(settings);
|
|
1475
|
+
// Record exactly what this RPC carried. A concurrent settings save may
|
|
1476
|
+
// already have advanced the desired fields and must remain pending for
|
|
1477
|
+
// the following new Turn.
|
|
1478
|
+
live.appliedModel = desiredModel;
|
|
1479
|
+
live.appliedReasoningEffort = desiredReasoningEffort;
|
|
1480
|
+
}
|
|
1481
|
+
publishAdmission();
|
|
1424
1482
|
const started = await injectionClient.turnStart({
|
|
1425
1483
|
threadId,
|
|
1426
1484
|
input: nativeInput,
|
|
1427
1485
|
...turnWorkspaceParams(live.runtime, live.workspace, live.sandbox),
|
|
1428
1486
|
approvalPolicy: live.approvalPolicy,
|
|
1429
|
-
...(live.model ? { model: live.model } : {}),
|
|
1430
|
-
...(live.reasoningEffort ? { effort: live.reasoningEffort } : {}),
|
|
1431
1487
|
});
|
|
1432
1488
|
if (pendingInput.observed) {
|
|
1433
1489
|
forgetPendingInput();
|
|
@@ -1449,6 +1505,13 @@ export class LocalAgentHost {
|
|
|
1449
1505
|
const baseDetail = codexRpcError(error, injectionMethod);
|
|
1450
1506
|
const startupDetail = live.forwarder.mcpStartupDetail();
|
|
1451
1507
|
const detail = startupDetail ? `${baseDetail} (${startupDetail})` : baseDetail;
|
|
1508
|
+
// A turn may open on the observer while this short-lived client is
|
|
1509
|
+
// initializing, converting the submission to steer. A rejected steer
|
|
1510
|
+
// does not fail that already-running Turn; only a new-Turn admission
|
|
1511
|
+
// owns the terminal failed edge.
|
|
1512
|
+
if (admissionPublished && injectionMethod === "turn/start") {
|
|
1513
|
+
live.publishTurnAdmissionFailure(detail);
|
|
1514
|
+
}
|
|
1452
1515
|
console.error(`[codex-live] session=${localThreadId} runtime=${live.runtime} injection failed: ${detail}`);
|
|
1453
1516
|
throw nativeLiveFailure(live.runtime, "native_message_injection_failed", `message injection via ${injectionMethod} failed`, detail);
|
|
1454
1517
|
}
|
|
@@ -1551,8 +1614,6 @@ export class LocalAgentHost {
|
|
|
1551
1614
|
claude.forwarder.finalizeStop();
|
|
1552
1615
|
}
|
|
1553
1616
|
removeManagedClaudeSettings(claude.bridgeDir);
|
|
1554
|
-
// Remove the throwaway skills --plugin-dir temp so it doesn't leak per launch.
|
|
1555
|
-
void claude.skillCleanup?.();
|
|
1556
1617
|
return;
|
|
1557
1618
|
}
|
|
1558
1619
|
const live = this.liveSessions.get(localThreadId);
|
|
@@ -1789,17 +1850,27 @@ export class LocalAgentHost {
|
|
|
1789
1850
|
throw new CodexRuntimeError(`cannot launch Claude from ${execution.provider} execution snapshot`, 422, "invalid_execution_snapshot");
|
|
1790
1851
|
}
|
|
1791
1852
|
const cwd = workspace.cwd;
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1853
|
+
const hasSkillSnapshot = execution.skills.length > 0 || execution.pluginSkills.length > 0;
|
|
1854
|
+
let skillPlugin = hasSkillSnapshot
|
|
1855
|
+
? await reuseClaudePlugin(localThreadId)
|
|
1856
|
+
: null;
|
|
1857
|
+
if (!skillPlugin && hasSkillSnapshot) {
|
|
1858
|
+
let snapshotSkills;
|
|
1859
|
+
try {
|
|
1860
|
+
snapshotSkills = await this.prepareExecutionSkills(execution);
|
|
1861
|
+
}
|
|
1862
|
+
catch (err) {
|
|
1863
|
+
console.error(`[session-snapshot] session=${localThreadId} skill materialization failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1864
|
+
return false;
|
|
1865
|
+
}
|
|
1866
|
+
try {
|
|
1867
|
+
skillPlugin = await materializeClaudePlugin(localThreadId, snapshotSkills.selectedSkills);
|
|
1868
|
+
}
|
|
1869
|
+
finally {
|
|
1870
|
+
await snapshotSkills.skillsCleanup();
|
|
1871
|
+
}
|
|
1799
1872
|
}
|
|
1800
1873
|
const model = execution.model ?? "";
|
|
1801
|
-
const skillPlugin = await materializeSkillPlugin(snapshotSkills.selectedSkills);
|
|
1802
|
-
void snapshotSkills.skillsCleanup();
|
|
1803
1874
|
const permissionMode = execution.permissionMode;
|
|
1804
1875
|
const launchExtraArgs = [
|
|
1805
1876
|
...(skillPlugin?.pluginDir ? ["--plugin-dir", skillPlugin.pluginDir] : []),
|
|
@@ -1876,7 +1947,6 @@ export class LocalAgentHost {
|
|
|
1876
1947
|
launchExtraArgs,
|
|
1877
1948
|
permissionMode,
|
|
1878
1949
|
...(forkIntent ? { forkIntent } : {}),
|
|
1879
|
-
...(skillPlugin?.cleanup ? { skillCleanup: skillPlugin.cleanup } : {}),
|
|
1880
1950
|
};
|
|
1881
1951
|
live.publishInterrupted = (responseId) => {
|
|
1882
1952
|
if (live.interruptedResponseId === responseId)
|
|
@@ -2411,6 +2481,21 @@ function sameSessionSnapshots(workspace, execution, opts) {
|
|
|
2411
2481
|
execution: opts.execution,
|
|
2412
2482
|
}));
|
|
2413
2483
|
}
|
|
2484
|
+
function sameImmutableSessionSnapshots(workspace, execution, opts) {
|
|
2485
|
+
const current = { ...execution, model: null, reasoningEffort: null };
|
|
2486
|
+
const requested = { ...opts.execution, model: null, reasoningEffort: null };
|
|
2487
|
+
return JSON.stringify(stableValue({ workspace, execution: current })) ===
|
|
2488
|
+
JSON.stringify(stableValue({ workspace: opts.workspace, execution: requested }));
|
|
2489
|
+
}
|
|
2490
|
+
function updateLiveCodexTurnSettings(live, opts) {
|
|
2491
|
+
if (!sameImmutableSessionSnapshots(live.workspace, live.execution, opts)) {
|
|
2492
|
+
return false;
|
|
2493
|
+
}
|
|
2494
|
+
live.execution = structuredClone(opts.execution);
|
|
2495
|
+
live.model = opts.execution.model ?? "";
|
|
2496
|
+
live.reasoningEffort = opts.execution.reasoningEffort ?? undefined;
|
|
2497
|
+
return true;
|
|
2498
|
+
}
|
|
2414
2499
|
/** Freeze the Session's permission choice into the explicit managed settings.
|
|
2415
2500
|
* Host/project settings may still contribute allow/deny rules, but changing
|
|
2416
2501
|
* their defaultMode cannot silently mutate an existing Session on resume. */
|
package/dist/runner/manager.d.ts
CHANGED
|
@@ -340,6 +340,7 @@ export declare class RunnerManager implements AgentCapabilities {
|
|
|
340
340
|
private isNativePaneBusy;
|
|
341
341
|
private isManagedNativeHandle;
|
|
342
342
|
private failActiveResponses;
|
|
343
|
+
private interruptActiveResponses;
|
|
343
344
|
/** Track the provider-authoritative response lifecycle. Native-pane busy
|
|
344
345
|
* classification consumes this level directly; output volume is separately
|
|
345
346
|
* grounded in tmux's own activity clock. */
|
package/dist/runner/manager.js
CHANGED
|
@@ -1335,6 +1335,7 @@ export class RunnerManager {
|
|
|
1335
1335
|
catch {
|
|
1336
1336
|
// The process signal below remains the authoritative shutdown path.
|
|
1337
1337
|
}
|
|
1338
|
+
this.interruptActiveResponses(handle);
|
|
1338
1339
|
this.failHandle(handle, reason, { failActiveResponses: false });
|
|
1339
1340
|
}
|
|
1340
1341
|
this.signalChild(handle.child, "SIGTERM", handle.processGroup);
|
|
@@ -1477,6 +1478,18 @@ export class RunnerManager {
|
|
|
1477
1478
|
});
|
|
1478
1479
|
}
|
|
1479
1480
|
}
|
|
1481
|
+
interruptActiveResponses(handle) {
|
|
1482
|
+
const responseIds = [...handle.activeResponseIds];
|
|
1483
|
+
handle.activeResponseIds.clear();
|
|
1484
|
+
const sessionId = this.currentTerminalSessionId(handle, handle.key);
|
|
1485
|
+
for (const responseId of responseIds) {
|
|
1486
|
+
this.mirrorListener?.(sessionId, {
|
|
1487
|
+
type: "session.interrupted",
|
|
1488
|
+
sessionId,
|
|
1489
|
+
responseId,
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1480
1493
|
/** Track the provider-authoritative response lifecycle. Native-pane busy
|
|
1481
1494
|
* classification consumes this level directly; output volume is separately
|
|
1482
1495
|
* grounded in tmux's own activity clock. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rynx-ai/runtime",
|
|
3
|
-
"version": "0.1.11-beta.
|
|
3
|
+
"version": "0.1.11-beta.24",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/rynx-ai/rynx.git",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"node-pty": "1.2.0-beta.15",
|
|
28
28
|
"smol-toml": "1.7.1",
|
|
29
29
|
"ws": "^8.21.0",
|
|
30
|
-
"@rynx-ai/core": "0.1.11-beta.
|
|
30
|
+
"@rynx-ai/core": "0.1.11-beta.24"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/ws": "^8.18.1"
|