@h-rig/runtime 0.0.6-alpha.32 → 0.0.6-alpha.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.
- package/dist/bin/rig-agent-dispatch.js +12 -0
- package/dist/bin/rig-agent.js +13 -15
- package/dist/src/control-plane/agent-wrapper.js +12 -0
- package/dist/src/control-plane/harness-main.js +1354 -1399
- package/dist/src/control-plane/hooks/completion-verification.js +510 -511
- package/dist/src/control-plane/hooks/inject-context.js +333 -333
- package/dist/src/control-plane/hooks/submodule-branch.js +1600 -1600
- package/dist/src/control-plane/hooks/task-runtime-start.js +1600 -1600
- package/dist/src/control-plane/native/git-ops.js +79 -152
- package/dist/src/control-plane/native/harness-cli.js +1354 -1399
- package/dist/src/control-plane/native/repo-ops.js +50 -50
- package/dist/src/control-plane/native/task-ops.js +1467 -1503
- package/dist/src/control-plane/native/verifier.js +34 -34
- package/dist/src/control-plane/pi-sessiond/bin.js +65 -2
- package/dist/src/control-plane/pi-sessiond/launcher.js +12 -0
- package/dist/src/control-plane/pi-sessiond/server.js +65 -2
- package/dist/src/control-plane/pi-sessiond/session-service.js +65 -2
- package/package.json +8 -8
|
@@ -245,16 +245,22 @@ function readBuildConfig() {
|
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
// packages/runtime/src/control-plane/
|
|
248
|
+
// packages/runtime/src/control-plane/native/git-native.ts
|
|
249
249
|
import { tmpdir } from "os";
|
|
250
|
-
import {
|
|
251
|
-
var
|
|
252
|
-
var
|
|
253
|
-
|
|
250
|
+
import { dirname as dirname2, isAbsolute, resolve as resolve2 } from "path";
|
|
251
|
+
var sharedGitNativeOutputDir = resolve2(tmpdir(), "rig-native");
|
|
252
|
+
var sharedGitNativeOutputPath = resolve2(sharedGitNativeOutputDir, `rig-git-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
253
|
+
|
|
254
|
+
// packages/runtime/src/control-plane/runtime/tooling/shell.ts
|
|
254
255
|
import { tmpdir as tmpdir2 } from "os";
|
|
255
|
-
import { basename
|
|
256
|
-
var
|
|
257
|
-
var
|
|
256
|
+
import { basename, dirname as dirname3, resolve as resolve3 } from "path";
|
|
257
|
+
var sharedNativeShellOutputDir = resolve3(tmpdir2(), "rig-native");
|
|
258
|
+
var sharedNativeShellOutputPath = resolve3(sharedNativeShellOutputDir, `rig-shell-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
259
|
+
// packages/runtime/src/control-plane/runtime/tooling/file-tools.ts
|
|
260
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
261
|
+
import { basename as basename2, dirname as dirname4, resolve as resolve4 } from "path";
|
|
262
|
+
var sharedNativeToolsOutputDir = resolve4(tmpdir3(), "rig-native");
|
|
263
|
+
var sharedNativeToolsOutputPath = resolve4(sharedNativeToolsOutputDir, `rig-tools-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
258
264
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
259
265
|
import { createPluginHost } from "@rig/core";
|
|
260
266
|
import { loadConfig } from "@rig/core/load-config";
|
|
@@ -469,7 +475,7 @@ function setScopeRules(rules) {
|
|
|
469
475
|
|
|
470
476
|
// packages/runtime/src/control-plane/hook-materializer.ts
|
|
471
477
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
472
|
-
import { dirname as
|
|
478
|
+
import { dirname as dirname5, resolve as resolve5 } from "path";
|
|
473
479
|
var MARKER_PLUGIN = "_rigPlugin";
|
|
474
480
|
var MARKER_HOOK_ID = "_rigHookId";
|
|
475
481
|
function matcherToString(matcher) {
|
|
@@ -483,7 +489,7 @@ function isPluginOwned(cmd) {
|
|
|
483
489
|
return typeof cmd[MARKER_PLUGIN] === "string";
|
|
484
490
|
}
|
|
485
491
|
function materializeHooks(projectRoot, entries) {
|
|
486
|
-
const settingsPath =
|
|
492
|
+
const settingsPath = resolve5(projectRoot, ".claude", "settings.json");
|
|
487
493
|
const existing = existsSync3(settingsPath) ? safeReadJson(settingsPath) : {};
|
|
488
494
|
const hooks = existing.hooks ?? {};
|
|
489
495
|
for (const event of Object.keys(hooks)) {
|
|
@@ -526,7 +532,7 @@ function materializeHooks(projectRoot, entries) {
|
|
|
526
532
|
} else {
|
|
527
533
|
delete next.hooks;
|
|
528
534
|
}
|
|
529
|
-
mkdirSync2(
|
|
535
|
+
mkdirSync2(dirname5(settingsPath), { recursive: true });
|
|
530
536
|
writeFileSync2(settingsPath, `${JSON.stringify(next, null, 2)}
|
|
531
537
|
`, "utf-8");
|
|
532
538
|
return settingsPath;
|
|
@@ -541,25 +547,25 @@ function safeReadJson(path) {
|
|
|
541
547
|
|
|
542
548
|
// packages/runtime/src/control-plane/skill-materializer.ts
|
|
543
549
|
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, readdirSync, rmSync, writeFileSync as writeFileSync3 } from "fs";
|
|
544
|
-
import { resolve as
|
|
550
|
+
import { resolve as resolve6 } from "path";
|
|
545
551
|
import { loadSkill } from "@rig/skill-loader";
|
|
546
552
|
var MARKER_FILENAME = ".rig-plugin";
|
|
547
553
|
function skillDirName(id) {
|
|
548
554
|
return id.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
549
555
|
}
|
|
550
556
|
async function materializeSkills(projectRoot, entries) {
|
|
551
|
-
const skillsRoot =
|
|
557
|
+
const skillsRoot = resolve6(projectRoot, ".pi", "skills");
|
|
552
558
|
if (existsSync4(skillsRoot)) {
|
|
553
559
|
for (const name of readdirSync(skillsRoot)) {
|
|
554
|
-
const dir =
|
|
555
|
-
if (existsSync4(
|
|
560
|
+
const dir = resolve6(skillsRoot, name);
|
|
561
|
+
if (existsSync4(resolve6(dir, MARKER_FILENAME))) {
|
|
556
562
|
rmSync(dir, { recursive: true, force: true });
|
|
557
563
|
}
|
|
558
564
|
}
|
|
559
565
|
}
|
|
560
566
|
const written = [];
|
|
561
567
|
for (const { pluginName, skill } of entries) {
|
|
562
|
-
const sourcePath =
|
|
568
|
+
const sourcePath = resolve6(projectRoot, skill.path);
|
|
563
569
|
if (!existsSync4(sourcePath)) {
|
|
564
570
|
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${sourcePath} does not exist`);
|
|
565
571
|
continue;
|
|
@@ -572,10 +578,10 @@ async function materializeSkills(projectRoot, entries) {
|
|
|
572
578
|
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${err instanceof Error ? err.message : err}`);
|
|
573
579
|
continue;
|
|
574
580
|
}
|
|
575
|
-
const dir =
|
|
581
|
+
const dir = resolve6(skillsRoot, skillDirName(skill.id));
|
|
576
582
|
mkdirSync3(dir, { recursive: true });
|
|
577
|
-
writeFileSync3(
|
|
578
|
-
writeFileSync3(
|
|
583
|
+
writeFileSync3(resolve6(dir, "SKILL.md"), body, "utf-8");
|
|
584
|
+
writeFileSync3(resolve6(dir, MARKER_FILENAME), `${JSON.stringify({ plugin: pluginName, skillId: skill.id }, null, 2)}
|
|
579
585
|
`, "utf-8");
|
|
580
586
|
written.push({ id: skill.id, pluginName, directory: dir });
|
|
581
587
|
}
|
|
@@ -643,11 +649,11 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
643
649
|
// packages/runtime/src/control-plane/tasks/source-aware-task-config-source.ts
|
|
644
650
|
import { spawnSync } from "child_process";
|
|
645
651
|
import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync, writeFileSync as writeFileSync4 } from "fs";
|
|
646
|
-
import { basename as basename3, join as join2, resolve as
|
|
652
|
+
import { basename as basename3, join as join2, resolve as resolve8 } from "path";
|
|
647
653
|
|
|
648
654
|
// packages/runtime/src/control-plane/tasks/legacy-task-config-source.ts
|
|
649
655
|
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
650
|
-
import { resolve as
|
|
656
|
+
import { resolve as resolve7 } from "path";
|
|
651
657
|
|
|
652
658
|
// packages/runtime/src/control-plane/tasks/task-record-reader.ts
|
|
653
659
|
async function findTaskById(reader, id) {
|
|
@@ -670,7 +676,7 @@ class LegacyTaskConfigReadError extends Error {
|
|
|
670
676
|
}
|
|
671
677
|
}
|
|
672
678
|
function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
673
|
-
const configPath = options.configPath ??
|
|
679
|
+
const configPath = options.configPath ?? resolve7(projectRoot, ".rig", "task-config.json");
|
|
674
680
|
const reader = {
|
|
675
681
|
async listTasks() {
|
|
676
682
|
return readLegacyTaskRecords(projectRoot, configPath);
|
|
@@ -681,7 +687,7 @@ function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
|
681
687
|
};
|
|
682
688
|
return reader;
|
|
683
689
|
}
|
|
684
|
-
function readLegacyTaskRecords(projectRoot, configPath =
|
|
690
|
+
function readLegacyTaskRecords(projectRoot, configPath = resolve7(projectRoot, ".rig", "task-config.json")) {
|
|
685
691
|
if (!existsSync5(configPath)) {
|
|
686
692
|
return [];
|
|
687
693
|
}
|
|
@@ -774,7 +780,7 @@ function isPlainRecord(candidate) {
|
|
|
774
780
|
var STATUS_LABELS = new Set(["ready", "blocked", "in-progress", "under-review", "failed", "cancelled"]);
|
|
775
781
|
var FILE_TASK_PATTERN = /\.(task\.)?json$/;
|
|
776
782
|
function createSourceAwareTaskConfigRecordReader(projectRoot, options = {}) {
|
|
777
|
-
const configPath = options.configPath ??
|
|
783
|
+
const configPath = options.configPath ?? resolve8(projectRoot, ".rig", "task-config.json");
|
|
778
784
|
const legacy = createLegacyTaskConfigRecordReader(projectRoot, { configPath });
|
|
779
785
|
const spawnFn = options.spawn ?? spawnSync;
|
|
780
786
|
const ghBinary = options.ghBinary ?? "gh";
|
|
@@ -857,7 +863,7 @@ function readMaterializedTaskMetadata(entry) {
|
|
|
857
863
|
return metadata;
|
|
858
864
|
}
|
|
859
865
|
function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
860
|
-
const jsonPath =
|
|
866
|
+
const jsonPath = resolve8(projectRoot, "rig.config.json");
|
|
861
867
|
if (existsSync6(jsonPath)) {
|
|
862
868
|
try {
|
|
863
869
|
const parsed = JSON.parse(readFileSync5(jsonPath, "utf8"));
|
|
@@ -869,7 +875,7 @@ function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
|
869
875
|
return null;
|
|
870
876
|
}
|
|
871
877
|
}
|
|
872
|
-
const tsPath =
|
|
878
|
+
const tsPath = resolve8(projectRoot, "rig.config.ts");
|
|
873
879
|
if (!existsSync6(tsPath)) {
|
|
874
880
|
return null;
|
|
875
881
|
}
|
|
@@ -905,7 +911,7 @@ function stripLegacyTaskConfigMetadata2(raw) {
|
|
|
905
911
|
return tasks;
|
|
906
912
|
}
|
|
907
913
|
function listFileBackedTasks(projectRoot, sourcePath) {
|
|
908
|
-
const directory =
|
|
914
|
+
const directory = resolve8(projectRoot, sourcePath);
|
|
909
915
|
if (!existsSync6(directory)) {
|
|
910
916
|
return [];
|
|
911
917
|
}
|
|
@@ -921,7 +927,7 @@ function listFileBackedTasks(projectRoot, sourcePath) {
|
|
|
921
927
|
return tasks;
|
|
922
928
|
}
|
|
923
929
|
function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
924
|
-
const file = findFileBackedTaskFile(
|
|
930
|
+
const file = findFileBackedTaskFile(resolve8(projectRoot, sourcePath), taskId);
|
|
925
931
|
if (!file) {
|
|
926
932
|
return null;
|
|
927
933
|
}
|
|
@@ -1123,12 +1129,6 @@ var CANONICAL_TASK_LIFECYCLE_STATUSES = new Set([
|
|
|
1123
1129
|
"completed",
|
|
1124
1130
|
"cancelled"
|
|
1125
1131
|
]);
|
|
1126
|
-
// packages/runtime/src/control-plane/native/git-native.ts
|
|
1127
|
-
import { tmpdir as tmpdir3 } from "os";
|
|
1128
|
-
import { dirname as dirname5, isAbsolute, resolve as resolve8 } from "path";
|
|
1129
|
-
var sharedGitNativeOutputDir = resolve8(tmpdir3(), "rig-native");
|
|
1130
|
-
var sharedGitNativeOutputPath = resolve8(sharedGitNativeOutputDir, `rig-git-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
1131
|
-
|
|
1132
1132
|
// packages/runtime/src/control-plane/native/utils.ts
|
|
1133
1133
|
import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
|
|
1134
1134
|
import { resolve as resolve11 } from "path";
|
|
@@ -273,11 +273,15 @@ function normalizeResponse(value) {
|
|
|
273
273
|
// packages/runtime/src/control-plane/pi-sessiond/session-service.ts
|
|
274
274
|
var BUILTIN_COMMANDS = [
|
|
275
275
|
{ name: "session", description: "Show session info and stats", source: "builtin" },
|
|
276
|
+
{ name: "settings", description: "Show worker session settings (model, thinking, name, cwd)", source: "builtin" },
|
|
277
|
+
{ name: "model", description: "Show or set the worker model: /model [provider/id]", source: "builtin" },
|
|
278
|
+
{ name: "thinking", description: "Set the worker thinking level: /thinking <off|minimal|low|medium|high|xhigh>", source: "builtin" },
|
|
276
279
|
{ name: "name", description: "Set session display name", source: "builtin" },
|
|
277
280
|
{ name: "compact", description: "Manually compact session context", source: "builtin" },
|
|
278
281
|
{ name: "reload", description: "Reload keybindings, extensions, skills, prompts, and themes", source: "builtin" },
|
|
279
282
|
{ name: "quit", description: "Detach from the current local Pi frontend", source: "builtin" }
|
|
280
283
|
];
|
|
284
|
+
var THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
281
285
|
|
|
282
286
|
class RigPiSessionService {
|
|
283
287
|
hub;
|
|
@@ -440,6 +444,64 @@ class RigPiSessionService {
|
|
|
440
444
|
const rest = args.join(" ").trim();
|
|
441
445
|
if (rawName === "session")
|
|
442
446
|
return { type: "done", message: formatSessionStats(active.runtime.session) };
|
|
447
|
+
if (rawName === "settings") {
|
|
448
|
+
const session = active.runtime.session;
|
|
449
|
+
const model = session.model;
|
|
450
|
+
return {
|
|
451
|
+
type: "done",
|
|
452
|
+
message: [
|
|
453
|
+
"Worker session settings:",
|
|
454
|
+
` model ${model ? `${model.provider}/${model.id}` : "(none)"} \u2014 change with /model <provider/id>`,
|
|
455
|
+
` thinking ${session.thinkingLevel} \u2014 change with /thinking <${THINKING_LEVELS.join("|")}>`,
|
|
456
|
+
` name ${session.sessionName || "(unnamed)"} \u2014 change with /name <name>`,
|
|
457
|
+
` cwd ${active.runtime.cwd}`,
|
|
458
|
+
` messages ${session.messages.length}`
|
|
459
|
+
].join(`
|
|
460
|
+
`)
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
if (rawName === "model") {
|
|
464
|
+
const session = active.runtime.session;
|
|
465
|
+
if (!rest) {
|
|
466
|
+
const available = session.modelRegistry.getAvailable().map((m) => `${m.provider}/${m.id}`);
|
|
467
|
+
const current = session.model ? `${session.model.provider}/${session.model.id}` : "(none)";
|
|
468
|
+
return {
|
|
469
|
+
type: "done",
|
|
470
|
+
message: [
|
|
471
|
+
`Current model: ${current}`,
|
|
472
|
+
available.length > 0 ? `Available: ${available.join(", ")}` : "No models with configured auth.",
|
|
473
|
+
"Switch with /model <provider/id>."
|
|
474
|
+
].join(`
|
|
475
|
+
`)
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
const [provider, ...idParts] = rest.split("/");
|
|
479
|
+
const id = idParts.join("/");
|
|
480
|
+
const target = provider && id ? session.modelRegistry.find(provider, id) : session.modelRegistry.getAvailable().find((m) => m.id === rest);
|
|
481
|
+
if (!target) {
|
|
482
|
+
return { type: "unsupported", message: `Unknown model "${rest}". Use /model to list available models.` };
|
|
483
|
+
}
|
|
484
|
+
try {
|
|
485
|
+
await session.setModel(target);
|
|
486
|
+
} catch (error) {
|
|
487
|
+
return { type: "unsupported", message: error instanceof Error ? error.message : String(error) };
|
|
488
|
+
}
|
|
489
|
+
this.publishStatus(active);
|
|
490
|
+
return { type: "done", message: `Model set to ${target.provider}/${target.id}.` };
|
|
491
|
+
}
|
|
492
|
+
if (rawName === "thinking") {
|
|
493
|
+
const session = active.runtime.session;
|
|
494
|
+
const level = rest.toLowerCase();
|
|
495
|
+
if (!THINKING_LEVELS.includes(level)) {
|
|
496
|
+
return {
|
|
497
|
+
type: "unsupported",
|
|
498
|
+
message: `Current thinking level: ${session.thinkingLevel}. Usage: /thinking <${THINKING_LEVELS.join("|")}>`
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
session.setThinkingLevel(level);
|
|
502
|
+
this.publishStatus(active);
|
|
503
|
+
return { type: "done", message: `Thinking level set to ${session.thinkingLevel}.` };
|
|
504
|
+
}
|
|
443
505
|
if (rawName === "name") {
|
|
444
506
|
if (!rest)
|
|
445
507
|
return { type: "unsupported", message: "Usage: /name <session name>" };
|
|
@@ -549,8 +611,9 @@ class RigPiSessionService {
|
|
|
549
611
|
}
|
|
550
612
|
publishHeartbeats() {
|
|
551
613
|
for (const active of this.activeBySession.values()) {
|
|
552
|
-
|
|
553
|
-
|
|
614
|
+
const busy = active.runtime.session.isStreaming || active.runtime.session.isCompacting || active.runtime.session.isBashRunning || active.runtime.session.pendingMessageCount > 0;
|
|
615
|
+
this.publishStatus(active);
|
|
616
|
+
if (busy) {
|
|
554
617
|
this.publishActivity(active, active.activity?.label ?? "active", "active", active.activity?.detail);
|
|
555
618
|
}
|
|
556
619
|
}
|
|
@@ -77,12 +77,24 @@ async function ensureRigPiSessionDaemon(input) {
|
|
|
77
77
|
stderr: "inherit"
|
|
78
78
|
});
|
|
79
79
|
proc.unref();
|
|
80
|
+
let exitCode = null;
|
|
81
|
+
proc.exited.then((code) => {
|
|
82
|
+
exitCode = code;
|
|
83
|
+
});
|
|
80
84
|
const deadline = Date.now() + (input.timeoutMs ?? 15000);
|
|
81
85
|
while (Date.now() < deadline) {
|
|
82
86
|
const ready = readDaemonReadyFile(readyFile);
|
|
83
87
|
const handle = ready ? await tryReady(ready) : null;
|
|
84
88
|
if (handle)
|
|
85
89
|
return handle;
|
|
90
|
+
if (exitCode !== null) {
|
|
91
|
+
throw new Error([
|
|
92
|
+
`Rig Pi session daemon exited with code ${exitCode} before becoming ready (${binPath}).`,
|
|
93
|
+
"Check the daemon stderr above. Run `rig doctor` to check Pi wiring,",
|
|
94
|
+
"set RIG_PI_BINARY to a working Pi build, or run without Pi via RIG_RUNTIME_ADAPTER=claude-code."
|
|
95
|
+
].join(`
|
|
96
|
+
`));
|
|
97
|
+
}
|
|
86
98
|
await sleep(100);
|
|
87
99
|
}
|
|
88
100
|
throw new Error([
|
|
@@ -271,11 +271,15 @@ function normalizeResponse(value) {
|
|
|
271
271
|
// packages/runtime/src/control-plane/pi-sessiond/session-service.ts
|
|
272
272
|
var BUILTIN_COMMANDS = [
|
|
273
273
|
{ name: "session", description: "Show session info and stats", source: "builtin" },
|
|
274
|
+
{ name: "settings", description: "Show worker session settings (model, thinking, name, cwd)", source: "builtin" },
|
|
275
|
+
{ name: "model", description: "Show or set the worker model: /model [provider/id]", source: "builtin" },
|
|
276
|
+
{ name: "thinking", description: "Set the worker thinking level: /thinking <off|minimal|low|medium|high|xhigh>", source: "builtin" },
|
|
274
277
|
{ name: "name", description: "Set session display name", source: "builtin" },
|
|
275
278
|
{ name: "compact", description: "Manually compact session context", source: "builtin" },
|
|
276
279
|
{ name: "reload", description: "Reload keybindings, extensions, skills, prompts, and themes", source: "builtin" },
|
|
277
280
|
{ name: "quit", description: "Detach from the current local Pi frontend", source: "builtin" }
|
|
278
281
|
];
|
|
282
|
+
var THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
279
283
|
|
|
280
284
|
class RigPiSessionService {
|
|
281
285
|
hub;
|
|
@@ -438,6 +442,64 @@ class RigPiSessionService {
|
|
|
438
442
|
const rest = args.join(" ").trim();
|
|
439
443
|
if (rawName === "session")
|
|
440
444
|
return { type: "done", message: formatSessionStats(active.runtime.session) };
|
|
445
|
+
if (rawName === "settings") {
|
|
446
|
+
const session = active.runtime.session;
|
|
447
|
+
const model = session.model;
|
|
448
|
+
return {
|
|
449
|
+
type: "done",
|
|
450
|
+
message: [
|
|
451
|
+
"Worker session settings:",
|
|
452
|
+
` model ${model ? `${model.provider}/${model.id}` : "(none)"} \u2014 change with /model <provider/id>`,
|
|
453
|
+
` thinking ${session.thinkingLevel} \u2014 change with /thinking <${THINKING_LEVELS.join("|")}>`,
|
|
454
|
+
` name ${session.sessionName || "(unnamed)"} \u2014 change with /name <name>`,
|
|
455
|
+
` cwd ${active.runtime.cwd}`,
|
|
456
|
+
` messages ${session.messages.length}`
|
|
457
|
+
].join(`
|
|
458
|
+
`)
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
if (rawName === "model") {
|
|
462
|
+
const session = active.runtime.session;
|
|
463
|
+
if (!rest) {
|
|
464
|
+
const available = session.modelRegistry.getAvailable().map((m) => `${m.provider}/${m.id}`);
|
|
465
|
+
const current = session.model ? `${session.model.provider}/${session.model.id}` : "(none)";
|
|
466
|
+
return {
|
|
467
|
+
type: "done",
|
|
468
|
+
message: [
|
|
469
|
+
`Current model: ${current}`,
|
|
470
|
+
available.length > 0 ? `Available: ${available.join(", ")}` : "No models with configured auth.",
|
|
471
|
+
"Switch with /model <provider/id>."
|
|
472
|
+
].join(`
|
|
473
|
+
`)
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
const [provider, ...idParts] = rest.split("/");
|
|
477
|
+
const id = idParts.join("/");
|
|
478
|
+
const target = provider && id ? session.modelRegistry.find(provider, id) : session.modelRegistry.getAvailable().find((m) => m.id === rest);
|
|
479
|
+
if (!target) {
|
|
480
|
+
return { type: "unsupported", message: `Unknown model "${rest}". Use /model to list available models.` };
|
|
481
|
+
}
|
|
482
|
+
try {
|
|
483
|
+
await session.setModel(target);
|
|
484
|
+
} catch (error) {
|
|
485
|
+
return { type: "unsupported", message: error instanceof Error ? error.message : String(error) };
|
|
486
|
+
}
|
|
487
|
+
this.publishStatus(active);
|
|
488
|
+
return { type: "done", message: `Model set to ${target.provider}/${target.id}.` };
|
|
489
|
+
}
|
|
490
|
+
if (rawName === "thinking") {
|
|
491
|
+
const session = active.runtime.session;
|
|
492
|
+
const level = rest.toLowerCase();
|
|
493
|
+
if (!THINKING_LEVELS.includes(level)) {
|
|
494
|
+
return {
|
|
495
|
+
type: "unsupported",
|
|
496
|
+
message: `Current thinking level: ${session.thinkingLevel}. Usage: /thinking <${THINKING_LEVELS.join("|")}>`
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
session.setThinkingLevel(level);
|
|
500
|
+
this.publishStatus(active);
|
|
501
|
+
return { type: "done", message: `Thinking level set to ${session.thinkingLevel}.` };
|
|
502
|
+
}
|
|
441
503
|
if (rawName === "name") {
|
|
442
504
|
if (!rest)
|
|
443
505
|
return { type: "unsupported", message: "Usage: /name <session name>" };
|
|
@@ -547,8 +609,9 @@ class RigPiSessionService {
|
|
|
547
609
|
}
|
|
548
610
|
publishHeartbeats() {
|
|
549
611
|
for (const active of this.activeBySession.values()) {
|
|
550
|
-
|
|
551
|
-
|
|
612
|
+
const busy = active.runtime.session.isStreaming || active.runtime.session.isCompacting || active.runtime.session.isBashRunning || active.runtime.session.pendingMessageCount > 0;
|
|
613
|
+
this.publishStatus(active);
|
|
614
|
+
if (busy) {
|
|
552
615
|
this.publishActivity(active, active.activity?.label ?? "active", "active", active.activity?.detail);
|
|
553
616
|
}
|
|
554
617
|
}
|
|
@@ -210,11 +210,15 @@ function normalizeResponse(value) {
|
|
|
210
210
|
// packages/runtime/src/control-plane/pi-sessiond/session-service.ts
|
|
211
211
|
var BUILTIN_COMMANDS = [
|
|
212
212
|
{ name: "session", description: "Show session info and stats", source: "builtin" },
|
|
213
|
+
{ name: "settings", description: "Show worker session settings (model, thinking, name, cwd)", source: "builtin" },
|
|
214
|
+
{ name: "model", description: "Show or set the worker model: /model [provider/id]", source: "builtin" },
|
|
215
|
+
{ name: "thinking", description: "Set the worker thinking level: /thinking <off|minimal|low|medium|high|xhigh>", source: "builtin" },
|
|
213
216
|
{ name: "name", description: "Set session display name", source: "builtin" },
|
|
214
217
|
{ name: "compact", description: "Manually compact session context", source: "builtin" },
|
|
215
218
|
{ name: "reload", description: "Reload keybindings, extensions, skills, prompts, and themes", source: "builtin" },
|
|
216
219
|
{ name: "quit", description: "Detach from the current local Pi frontend", source: "builtin" }
|
|
217
220
|
];
|
|
221
|
+
var THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
218
222
|
|
|
219
223
|
class RigPiSessionService {
|
|
220
224
|
hub;
|
|
@@ -377,6 +381,64 @@ class RigPiSessionService {
|
|
|
377
381
|
const rest = args.join(" ").trim();
|
|
378
382
|
if (rawName === "session")
|
|
379
383
|
return { type: "done", message: formatSessionStats(active.runtime.session) };
|
|
384
|
+
if (rawName === "settings") {
|
|
385
|
+
const session = active.runtime.session;
|
|
386
|
+
const model = session.model;
|
|
387
|
+
return {
|
|
388
|
+
type: "done",
|
|
389
|
+
message: [
|
|
390
|
+
"Worker session settings:",
|
|
391
|
+
` model ${model ? `${model.provider}/${model.id}` : "(none)"} \u2014 change with /model <provider/id>`,
|
|
392
|
+
` thinking ${session.thinkingLevel} \u2014 change with /thinking <${THINKING_LEVELS.join("|")}>`,
|
|
393
|
+
` name ${session.sessionName || "(unnamed)"} \u2014 change with /name <name>`,
|
|
394
|
+
` cwd ${active.runtime.cwd}`,
|
|
395
|
+
` messages ${session.messages.length}`
|
|
396
|
+
].join(`
|
|
397
|
+
`)
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
if (rawName === "model") {
|
|
401
|
+
const session = active.runtime.session;
|
|
402
|
+
if (!rest) {
|
|
403
|
+
const available = session.modelRegistry.getAvailable().map((m) => `${m.provider}/${m.id}`);
|
|
404
|
+
const current = session.model ? `${session.model.provider}/${session.model.id}` : "(none)";
|
|
405
|
+
return {
|
|
406
|
+
type: "done",
|
|
407
|
+
message: [
|
|
408
|
+
`Current model: ${current}`,
|
|
409
|
+
available.length > 0 ? `Available: ${available.join(", ")}` : "No models with configured auth.",
|
|
410
|
+
"Switch with /model <provider/id>."
|
|
411
|
+
].join(`
|
|
412
|
+
`)
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
const [provider, ...idParts] = rest.split("/");
|
|
416
|
+
const id = idParts.join("/");
|
|
417
|
+
const target = provider && id ? session.modelRegistry.find(provider, id) : session.modelRegistry.getAvailable().find((m) => m.id === rest);
|
|
418
|
+
if (!target) {
|
|
419
|
+
return { type: "unsupported", message: `Unknown model "${rest}". Use /model to list available models.` };
|
|
420
|
+
}
|
|
421
|
+
try {
|
|
422
|
+
await session.setModel(target);
|
|
423
|
+
} catch (error) {
|
|
424
|
+
return { type: "unsupported", message: error instanceof Error ? error.message : String(error) };
|
|
425
|
+
}
|
|
426
|
+
this.publishStatus(active);
|
|
427
|
+
return { type: "done", message: `Model set to ${target.provider}/${target.id}.` };
|
|
428
|
+
}
|
|
429
|
+
if (rawName === "thinking") {
|
|
430
|
+
const session = active.runtime.session;
|
|
431
|
+
const level = rest.toLowerCase();
|
|
432
|
+
if (!THINKING_LEVELS.includes(level)) {
|
|
433
|
+
return {
|
|
434
|
+
type: "unsupported",
|
|
435
|
+
message: `Current thinking level: ${session.thinkingLevel}. Usage: /thinking <${THINKING_LEVELS.join("|")}>`
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
session.setThinkingLevel(level);
|
|
439
|
+
this.publishStatus(active);
|
|
440
|
+
return { type: "done", message: `Thinking level set to ${session.thinkingLevel}.` };
|
|
441
|
+
}
|
|
380
442
|
if (rawName === "name") {
|
|
381
443
|
if (!rest)
|
|
382
444
|
return { type: "unsupported", message: "Usage: /name <session name>" };
|
|
@@ -486,8 +548,9 @@ class RigPiSessionService {
|
|
|
486
548
|
}
|
|
487
549
|
publishHeartbeats() {
|
|
488
550
|
for (const active of this.activeBySession.values()) {
|
|
489
|
-
|
|
490
|
-
|
|
551
|
+
const busy = active.runtime.session.isStreaming || active.runtime.session.isCompacting || active.runtime.session.isBashRunning || active.runtime.session.pendingMessageCount > 0;
|
|
552
|
+
this.publishStatus(active);
|
|
553
|
+
if (busy) {
|
|
491
554
|
this.publishActivity(active, active.activity?.label ?? "active", "active", active.activity?.detail);
|
|
492
555
|
}
|
|
493
556
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-rig/runtime",
|
|
3
|
-
"version": "0.0.6-alpha.
|
|
3
|
+
"version": "0.0.6-alpha.34",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Rig package",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -63,14 +63,14 @@
|
|
|
63
63
|
"main": "./dist/src/index.js",
|
|
64
64
|
"module": "./dist/src/index.js",
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@earendil-works/pi-coding-agent": "npm:@h-rig/pi-coding-agent@0.0.6-alpha.
|
|
66
|
+
"@earendil-works/pi-coding-agent": "npm:@h-rig/pi-coding-agent@0.0.6-alpha.34",
|
|
67
67
|
"@libsql/client": "^0.17.2",
|
|
68
|
-
"@rig/contracts": "npm:@h-rig/contracts@0.0.6-alpha.
|
|
69
|
-
"@rig/core": "npm:@h-rig/core@0.0.6-alpha.
|
|
70
|
-
"@rig/hook-kit": "npm:@h-rig/hook-kit@0.0.6-alpha.
|
|
71
|
-
"@rig/shared": "npm:@h-rig/shared@0.0.6-alpha.
|
|
72
|
-
"@rig/skill-loader": "npm:@h-rig/skill-loader@0.0.6-alpha.
|
|
73
|
-
"@rig/validator-kit": "npm:@h-rig/validator-kit@0.0.6-alpha.
|
|
68
|
+
"@rig/contracts": "npm:@h-rig/contracts@0.0.6-alpha.34",
|
|
69
|
+
"@rig/core": "npm:@h-rig/core@0.0.6-alpha.34",
|
|
70
|
+
"@rig/hook-kit": "npm:@h-rig/hook-kit@0.0.6-alpha.34",
|
|
71
|
+
"@rig/shared": "npm:@h-rig/shared@0.0.6-alpha.34",
|
|
72
|
+
"@rig/skill-loader": "npm:@h-rig/skill-loader@0.0.6-alpha.34",
|
|
73
|
+
"@rig/validator-kit": "npm:@h-rig/validator-kit@0.0.6-alpha.34",
|
|
74
74
|
"effect": "4.0.0-beta.78",
|
|
75
75
|
"smol-toml": "^1.6.0"
|
|
76
76
|
}
|