sisyphi 1.2.14 → 1.2.15

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/cli.js CHANGED
@@ -192,11 +192,11 @@ var init_config = __esm({
192
192
  "use strict";
193
193
  init_paths();
194
194
  DEFAULT_CONFIG = {
195
- model: "claude-opus-4-7[1m]",
195
+ model: "claude-opus-4-8[1m]",
196
196
  pollIntervalMs: 5e3,
197
197
  statusBarRenderTicks: 4,
198
198
  orchestratorEffort: "xhigh",
199
- agentEffort: "medium",
199
+ agentEffort: "high",
200
200
  notifications: {
201
201
  enabled: true,
202
202
  sound: "/System/Library/Sounds/Hero.aiff"
@@ -636,6 +636,7 @@ var init_notify = __esm({
636
636
 
637
637
  // src/daemon/ask-store.ts
638
638
  import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync11, readdirSync as readdirSync3 } from "fs";
639
+ import { basename as basename3 } from "path";
639
640
  function maybeNotifyOnAskCreated(cwd, sessionId, meta) {
640
641
  if (process.env.NODE_ENV === "test" || process.env.SISYPHUS_DISABLE_NOTIFY === "1") return;
641
642
  const isActionable = meta.kind !== void 0 && ACTIONABLE_KINDS.has(meta.kind);
@@ -899,7 +900,7 @@ var init_exec = __esm({
899
900
  // src/daemon/frontmatter.ts
900
901
  import { readFileSync as readFileSync15, existsSync as existsSync14, readdirSync as readdirSync5 } from "fs";
901
902
  import { homedir as homedir8 } from "os";
902
- import { join as join15, basename as basename4 } from "path";
903
+ import { join as join15, basename as basename5 } from "path";
903
904
  function parseAgentFrontmatter(content) {
904
905
  const match = content.match(/^---\n([\s\S]*?)\n---/);
905
906
  if (!match) return {};
@@ -944,7 +945,7 @@ function discoverAgentTypes(pluginDir, cwd) {
944
945
  }
945
946
  for (const file of files) {
946
947
  if (!file.endsWith(".md") || file === "CLAUDE.md") continue;
947
- const name = basename4(file, ".md");
948
+ const name = basename5(file, ".md");
948
949
  const qualifiedName = prefix ? `${prefix}:${name}` : name;
949
950
  if (seen.has(qualifiedName)) continue;
950
951
  seen.add(qualifiedName);
@@ -996,7 +997,7 @@ var init_effort_render = __esm({
996
997
 
997
998
  // src/daemon/extensions.ts
998
999
  import { existsSync as existsSync15, readFileSync as readFileSync16, readdirSync as readdirSync6, copyFileSync as copyFileSync2, mkdirSync as mkdirSync8, statSync as statSync3, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "fs";
999
- import { resolve as resolve6, join as join16, basename as basename5, relative } from "path";
1000
+ import { resolve as resolve6, join as join16, basename as basename6, relative } from "path";
1000
1001
  function resolveBundledTemplateDir(kind) {
1001
1002
  const built = resolve6(import.meta.dirname, "../templates", kind);
1002
1003
  if (existsSync15(built)) return built;
@@ -2799,7 +2800,7 @@ var init_grove = __esm({
2799
2800
  // src/cli/cloud/repo.ts
2800
2801
  import { spawnSync as spawnSync5 } from "child_process";
2801
2802
  import { existsSync as existsSync35 } from "fs";
2802
- import { basename as basename7, join as join30 } from "path";
2803
+ import { basename as basename8, join as join30 } from "path";
2803
2804
  function captureGit(args2, cwd) {
2804
2805
  const result = spawnSync5("git", args2, {
2805
2806
  encoding: "utf-8",
@@ -2813,8 +2814,8 @@ function captureGit(args2, cwd) {
2813
2814
  }
2814
2815
  function inferRepoName(cwd) {
2815
2816
  const { stdout, ok } = captureGit(["rev-parse", "--show-toplevel"], cwd);
2816
- if (ok && stdout) return basename7(stdout);
2817
- return basename7(cwd ?? process.cwd());
2817
+ if (ok && stdout) return basename8(stdout);
2818
+ return basename8(cwd ?? process.cwd());
2818
2819
  }
2819
2820
  function getOriginUrl(cwd) {
2820
2821
  const { stdout, ok } = captureGit(["remote", "get-url", "origin"], cwd);
@@ -3292,7 +3293,7 @@ var init_respawn_guard = __esm({
3292
3293
  });
3293
3294
 
3294
3295
  // src/daemon/companion-commentary.ts
3295
- import { basename as basename8 } from "path";
3296
+ import { basename as basename9 } from "path";
3296
3297
  import { z as z2 } from "zod";
3297
3298
  var CommentaryZodSchema, ENDURANCE_TIERS;
3298
3299
  var init_companion_commentary = __esm({
@@ -3522,7 +3523,7 @@ var init_ask_visual = __esm({
3522
3523
  // src/daemon/server.ts
3523
3524
  import { createServer } from "net";
3524
3525
  import { unlinkSync as unlinkSync7, existsSync as existsSync48, writeFileSync as writeFileSync24, readFileSync as readFileSync45, mkdirSync as mkdirSync20, readdirSync as readdirSync15, rmSync as rmSync11, chmodSync as chmodSync4 } from "fs";
3525
- import { join as join37, basename as basename9, dirname as dirname15 } from "path";
3526
+ import { join as join37, basename as basename10, dirname as dirname15 } from "path";
3526
3527
  import { scanInbox } from "@crouton-kit/humanloop";
3527
3528
  function registryPath() {
3528
3529
  return join37(globalDir(), "session-registry.json");
@@ -3787,6 +3788,7 @@ function ensureSisyphusInitLua() {
3787
3788
 
3788
3789
  // src/cli/tmux-setup.ts
3789
3790
  var DEFAULT_CYCLE_KEY = "M-s";
3791
+ var DEFAULT_CYCLE_BACK_KEY = "M-S";
3790
3792
  var DEFAULT_PREFIX_KEY = "C-s";
3791
3793
  var KEY_TABLE = "sisyphus";
3792
3794
  var SISYPHUS_CONF_MARKER = "# sisyphus-managed \u2014 do not edit";
@@ -3958,6 +3960,8 @@ var OPEN_BIN = "$HOME/.sisyphus/bin/sisyphus-open";
3958
3960
  var CYCLE_SCRIPT = `#!/bin/bash
3959
3961
  # Target by $N session ID (column 5 in TSV) \u2014 tmux -t <name> can substring-match
3960
3962
  # the wrong session under sparse env.
3963
+ # Arg $1: "prev" cycles backward (M-S); anything else cycles forward (M-s).
3964
+ dir="\${1:-next}"
3961
3965
  MANIFEST="$HOME/.sisyphus/sessions-manifest.tsv"
3962
3966
  if [ ! -f "$MANIFEST" ]; then
3963
3967
  tmux display-message "sisyphus: no manifest \u2014 daemon running?"
@@ -3984,7 +3988,11 @@ if (( \${#session_ids[@]} <= 1 )); then
3984
3988
  fi
3985
3989
  for (( i=0; i<\${#session_ids[@]}; i++ )); do
3986
3990
  if [ "\${session_ids[$i]}" = "$current_id" ]; then
3987
- next=$(( (i + 1) % \${#session_ids[@]} ))
3991
+ if [ "$dir" = "prev" ]; then
3992
+ next=$(( (i - 1 + \${#session_ids[@]}) % \${#session_ids[@]} ))
3993
+ else
3994
+ next=$(( (i + 1) % \${#session_ids[@]} ))
3995
+ fi
3988
3996
  tmux switch-client -t "\${session_ids[$next]}"
3989
3997
  exit 0
3990
3998
  fi
@@ -5117,7 +5125,7 @@ async function setupTmuxKeybind(cycleKey = DEFAULT_CYCLE_KEY, prefixKey = DEFAUL
5117
5125
  };
5118
5126
  }
5119
5127
  if (!opts.force) {
5120
- for (const [label, key] of [["cycle", cycleKey], ["prefix", prefixKey]]) {
5128
+ for (const [label, key] of [["cycle", cycleKey], ["cycle-back", DEFAULT_CYCLE_BACK_KEY], ["prefix", prefixKey]]) {
5121
5129
  const existing = getExistingBinding(key);
5122
5130
  if (existing !== null && !isSisyphusBinding(existing)) {
5123
5131
  return {
@@ -5156,8 +5164,10 @@ Or run "sis admin check check-keybinds" for the full decision tree (live-only in
5156
5164
  const bindings = [
5157
5165
  // C-s → display-menu top-level (descriptor-driven)
5158
5166
  generateTopLevelBinding(prefixKey, KEYMAP.topLevel, scriptsDir),
5159
- // M-s → cycle (unchanged)
5160
- `bind-key -T root ${cycleKey} run-shell ${cycleScriptPath()}`
5167
+ // M-s → cycle forward (unchanged)
5168
+ `bind-key -T root ${cycleKey} run-shell ${cycleScriptPath()}`,
5169
+ // M-S → cycle backward (same script, "prev" direction)
5170
+ `bind-key -T root ${DEFAULT_CYCLE_BACK_KEY} run-shell "${cycleScriptPath()} prev"`
5161
5171
  // smart-kill is reachable via the sisyphus prefix menu (C-s x) — see KEYMAP.topLevel.
5162
5172
  // We deliberately don't override `prefix x` so users keep their default tmux kill-pane.
5163
5173
  ];
@@ -5231,6 +5241,7 @@ function removeTmuxKeybind() {
5231
5241
  }
5232
5242
  try {
5233
5243
  execSync(`tmux unbind-key -T root ${DEFAULT_CYCLE_KEY}`, { stdio: "pipe" });
5244
+ execSync(`tmux unbind-key -T root ${DEFAULT_CYCLE_BACK_KEY}`, { stdio: "pipe" });
5234
5245
  execSync(`tmux unbind-key -T root ${DEFAULT_PREFIX_KEY}`, { stdio: "pipe" });
5235
5246
  const output = execSync(`tmux list-keys -T ${KEY_TABLE}`, { stdio: ["pipe", "pipe", "pipe"] }).toString();
5236
5247
  for (const line of output.split("\n")) {
@@ -5703,7 +5714,7 @@ function exitForError(kind) {
5703
5714
  function exitError(err) {
5704
5715
  const e = normalizeError(err);
5705
5716
  process.stdout.write(
5706
- JSON.stringify({ ok: false, schema_version: 1, error: e }) + "\n"
5717
+ JSON.stringify({ ok: false, error: e }) + "\n"
5707
5718
  );
5708
5719
  process.exit(exitForError(e.kind));
5709
5720
  }
@@ -5714,7 +5725,7 @@ function exitUsage(code, message, fields = {}) {
5714
5725
  // src/cli/output.ts
5715
5726
  function emitJsonOk(data = {}) {
5716
5727
  process.stdout.write(
5717
- JSON.stringify({ ok: true, schema_version: 1, data }) + "\n"
5728
+ JSON.stringify({ ok: true, data }) + "\n"
5718
5729
  );
5719
5730
  }
5720
5731
 
@@ -5749,8 +5760,8 @@ Input
5749
5760
  --accept-cwd-mismatch optional \u2014 bypass the tmux session home check when cwd intentionally differs
5750
5761
 
5751
5762
  Output (stdout, JSON)
5752
- { ok, schema_version: 1, data: { sessionId, tmuxSessionName? } }
5753
- on error: { ok: false, schema_version: 1, error: { code, message } }
5763
+ { ok, data: { sessionId, tmuxSessionName? } }
5764
+ on error: { ok: false, error: { code, message } }
5754
5765
 
5755
5766
  Effects
5756
5767
  Creates a new session record on the daemon.
@@ -5882,7 +5893,7 @@ Input
5882
5893
  [session-id] optional. Defaults to $SISYPHUS_SESSION_ID.
5883
5894
 
5884
5895
  Output (stdout, JSON)
5885
- ok, schema_version: 1, data: { session }
5896
+ ok, data: { session }
5886
5897
  session is null when no matching session is found.
5887
5898
 
5888
5899
  Effects
@@ -6001,7 +6012,7 @@ Input
6001
6012
  --all optional boolean. Include sessions from all project directories.
6002
6013
  --cwd PATH optional. Project directory override; default is $SISYPHUS_CWD or cwd.
6003
6014
 
6004
- Output (stdout, JSON, schema_version: 2)
6015
+ Output (stdout, JSON)
6005
6016
  items object[]. Sorted by createdAt ascending; stable across pages.
6006
6017
  Fields: {id, name?, task, status, agentCount, createdAt, cwd?, handoff?}.
6007
6018
  next_cursor string | null. Pass to the next call. null on the last page.
@@ -6041,7 +6052,7 @@ Exit codes: 0 ok | 2 usage | 3 not_found.`).option("--all", "List sessions acros
6041
6052
  const next_cursor = hasMore ? encodeCursor(page[page.length - 1].createdAt, page[page.length - 1].id) : null;
6042
6053
  const total = requestedScope.length;
6043
6054
  process.stdout.write(
6044
- JSON.stringify({ ok: true, schema_version: 2, data: { items: page, next_cursor, total } }) + "\n"
6055
+ JSON.stringify({ ok: true, data: { items: page, next_cursor, total } }) + "\n"
6045
6056
  );
6046
6057
  });
6047
6058
  }
@@ -6109,7 +6120,7 @@ Input
6109
6120
  --paste-only optional. Paste without pressing Enter; caller submits manually.
6110
6121
 
6111
6122
  Output (stdout, JSON)
6112
- ok, schema_version: 1, data: { target, submit }
6123
+ ok, data: { target, submit }
6113
6124
 
6114
6125
  Effects
6115
6126
  Types text into the orchestrator tmux pane and optionally submits it.
@@ -6140,7 +6151,7 @@ Input
6140
6151
  --paste-only optional. Paste without pressing Enter; caller submits manually.
6141
6152
 
6142
6153
  Output (stdout, JSON)
6143
- ok, schema_version: 1, data: { target, submit }
6154
+ ok, data: { target, submit }
6144
6155
 
6145
6156
  Effects
6146
6157
  Types text into the agent tmux pane and optionally submits it.
@@ -6232,7 +6243,7 @@ Input
6232
6243
  --head <n> optional \u2014 emit only the first N turns
6233
6244
 
6234
6245
  Output (stdout, JSONL)
6235
- one JSON object per line; no {ok, schema_version} envelope (stream contract).
6246
+ one JSON object per line; no {ok} envelope (stream contract).
6236
6247
  fields: { role: "user"|"assistant", timestamp: ISO-8601, content: message content }
6237
6248
  ordered oldest-first within the selected cycle.
6238
6249
 
@@ -6301,7 +6312,7 @@ Input
6301
6312
  --head <n> optional \u2014 emit only the first N turns
6302
6313
 
6303
6314
  Output (stdout, JSONL)
6304
- one JSON object per line; no {ok, schema_version} envelope (stream contract).
6315
+ one JSON object per line; no {ok} envelope (stream contract).
6305
6316
  fields: { role: "user"|"assistant", timestamp: ISO-8601, content: message content }
6306
6317
  ordered oldest-first.
6307
6318
 
@@ -6357,7 +6368,7 @@ Input
6357
6368
  --agent <agentId> optional. Routes to a specific agent inbox instead of orchestrator.
6358
6369
 
6359
6370
  Output (stdout, JSON)
6360
- ok, schema_version: 1, data: { sessionId, agentId? }
6371
+ ok, data: { sessionId, agentId? }
6361
6372
 
6362
6373
  Effects
6363
6374
  Queues the message in the daemon inbox for the target; delivered on next cycle.
@@ -6397,7 +6408,7 @@ Exit codes: 0 ok | 2 usage (missing content or --session) | 3 not_found.`
6397
6408
 
6398
6409
  // src/cli/commands/ask.ts
6399
6410
  import { existsSync as existsSync12, readFileSync as readFileSync12, unlinkSync as unlinkSync3, watchFile, unwatchFile } from "fs";
6400
- import { basename as basename3, join as join13, resolve as resolve5 } from "path";
6411
+ import { basename as basename4, join as join13, resolve as resolve5 } from "path";
6401
6412
  import { ulid } from "ulid";
6402
6413
 
6403
6414
  // src/shared/ask-schema.ts
@@ -6563,7 +6574,7 @@ Input
6563
6574
  <file> required \u2014 path to a valid deck JSON file
6564
6575
  --session <id> optional \u2014 session id (defaults to SISYPHUS_SESSION_ID)
6565
6576
 
6566
- Output (stdout, bare JSON \u2014 NOT the standard {ok, schema_version, data} envelope)
6577
+ Output (stdout, bare JSON \u2014 NOT the standard {ok, data} envelope)
6567
6578
  { "responses": [{ "id", "selectedOptionId"?, "freetext"? }, ...], "completedAt" }
6568
6579
  Branch on each response by its interaction \`id\`.
6569
6580
  on error: stderr diagnostic + non-zero exit
@@ -6586,7 +6597,7 @@ Input
6586
6597
  --body <b> optional \u2014 markdown body describing what the user is approving
6587
6598
  --session <id> optional \u2014 session id (defaults to SISYPHUS_SESSION_ID)
6588
6599
 
6589
- Output (stdout, bare JSON \u2014 NOT the standard {ok, schema_version, data} envelope)
6600
+ Output (stdout, bare JSON \u2014 NOT the standard {ok, data} envelope)
6590
6601
  { "askId", "approved": boolean, "completedAt", "responses" }
6591
6602
  on error: stderr diagnostic + non-zero exit
6592
6603
 
@@ -6607,7 +6618,7 @@ Input
6607
6618
  --body <b> optional \u2014 markdown body
6608
6619
  --session <id> optional \u2014 session id (defaults to SISYPHUS_SESSION_ID)
6609
6620
 
6610
- Output (stdout, bare JSON \u2014 NOT the standard {ok, schema_version, data} envelope)
6621
+ Output (stdout, bare JSON \u2014 NOT the standard {ok, data} envelope)
6611
6622
  { "askId" }
6612
6623
  on error: stderr diagnostic + non-zero exit
6613
6624
 
@@ -6617,7 +6628,7 @@ Effects
6617
6628
  Exit codes: 0 ok | 2 usage (missing session)
6618
6629
  `;
6619
6630
  var REVIEW_BRANCH_HELP = `
6620
- Line-by-line markdown annotation workflow. The agent submits the file; the user opens it in their editor from the dashboard inbox, annotates per-line with <Space>c, and submits with <Space>s or the dashboard "Submit" action. Multiple open/close cycles are supported \u2014 the draft persists until explicitly submitted.
6631
+ Line-by-line markdown annotation workflow. The agent submits the file; in tmux an editor pane opens next to the agent (also reachable from the dashboard inbox). The user annotates per-line with <Space>c and submits with <Space>s. Multiple open/close cycles are supported \u2014 the draft persists until explicitly submitted.
6621
6632
 
6622
6633
  Use when surfacing a document the user should annotate per-line rather than pick options on. For a global yes/no, use \`sis ask approve\`. For named alternatives, use \`sis ask deck submit\`.
6623
6634
 
@@ -6633,13 +6644,13 @@ Input
6633
6644
  <file> required \u2014 must exist and end in .md
6634
6645
  --session <id> optional \u2014 session id (defaults to SISYPHUS_SESSION_ID)
6635
6646
 
6636
- Output (stdout, bare JSON \u2014 NOT the standard {ok, schema_version, data} envelope)
6647
+ Output (stdout, bare JSON \u2014 NOT the standard {ok, data} envelope)
6637
6648
  { "askId", "file", "output": { "kind": "review", "feedback": { ... }, "completedAt" } }
6638
6649
  FeedbackResult fields: file, submitted, approved, comments[{ line, endLine, lineText, quote?, colStart?, colEnd?, comment, createdAt }], submittedAt, savedAt.
6639
6650
  on error: stderr diagnostic + non-zero exit
6640
6651
 
6641
6652
  Effects
6642
- Creates an ask in the session store, blocks until the user submits the review, then marks it answered.
6653
+ Creates an ask in the session store. In tmux, splits an editor pane next to the caller running the annotator (\`ask review open\`) so the user lands in the editor; also surfaces in the dashboard inbox. Blocks until the user submits the review, then marks it answered. Set SISYPHUS_DISABLE_ASK_PANE=1 to suppress the pane (dashboard-only).
6643
6654
 
6644
6655
  Exit codes: 0 ok | 2 usage (file not found, not .md, missing session)
6645
6656
  `;
@@ -6650,7 +6661,7 @@ Input
6650
6661
  <askId> required \u2014 26-character ULID of a pending review ask
6651
6662
  --session <id> optional \u2014 session id (defaults to SISYPHUS_SESSION_ID)
6652
6663
 
6653
- Output (stdout, bare JSON \u2014 NOT the standard {ok, schema_version, data} envelope)
6664
+ Output (stdout, bare JSON \u2014 NOT the standard {ok, data} envelope)
6654
6665
  { "askId", "submitted": boolean, "comments": number }
6655
6666
  on error: stderr diagnostic + non-zero exit
6656
6667
 
@@ -6666,7 +6677,7 @@ Input
6666
6677
  <askId> required \u2014 26-character ULID of a pending review ask
6667
6678
  --session <id> optional \u2014 session id (defaults to SISYPHUS_SESSION_ID)
6668
6679
 
6669
- Output (stdout, bare JSON \u2014 NOT the standard {ok, schema_version, data} envelope)
6680
+ Output (stdout, bare JSON \u2014 NOT the standard {ok, data} envelope)
6670
6681
  { "askId", "submitted": true, "comments": number }
6671
6682
  on error: stderr diagnostic + non-zero exit
6672
6683
 
@@ -6694,7 +6705,7 @@ Input
6694
6705
  <askId> required \u2014 26-character ULID
6695
6706
  --session <id> optional \u2014 session id (defaults to SISYPHUS_SESSION_ID)
6696
6707
 
6697
- Output (stdout, bare JSON \u2014 NOT the standard {ok, schema_version, data} envelope)
6708
+ Output (stdout, bare JSON \u2014 NOT the standard {ok, data} envelope)
6698
6709
  Same JSON as the original submitting command would have returned ({ responses, completedAt } for decks; { kind: 'review', feedback, completedAt } for reviews).
6699
6710
  on error: stderr diagnostic + non-zero exit
6700
6711
 
@@ -6712,7 +6723,7 @@ Input
6712
6723
  <askId> required \u2014 26-character ULID
6713
6724
  --session <id> optional \u2014 session id (defaults to SISYPHUS_SESSION_ID)
6714
6725
 
6715
- Output (stdout, bare JSON \u2014 NOT the standard {ok, schema_version, data} envelope)
6726
+ Output (stdout, bare JSON \u2014 NOT the standard {ok, data} envelope)
6716
6727
  { "askId", "status": "pending" | "in-progress" | "answered" | "not-found", "completedAt"?, "output"? }
6717
6728
  on error: stderr diagnostic + non-zero exit
6718
6729
 
@@ -6729,7 +6740,7 @@ Input
6729
6740
  --cursor <c> optional \u2014 opaque pagination token from a previous next_cursor
6730
6741
  --session <id> optional \u2014 session id (defaults to SISYPHUS_SESSION_ID)
6731
6742
 
6732
- Output (stdout, bare JSON \u2014 NOT the standard {ok, schema_version, data} envelope)
6743
+ Output (stdout, bare JSON \u2014 NOT the standard {ok, data} envelope)
6733
6744
  { "items": [{ "askId", "title"?, "kind"?, "askedAt", "blocking", "askedBy" }], "next_cursor": string | null, "total": number }
6734
6745
  Pass next_cursor to the next call to page; null means end of list.
6735
6746
  on error: stderr diagnostic + non-zero exit
@@ -6749,7 +6760,7 @@ Input
6749
6760
  --watch optional \u2014 live-update the pane on edits
6750
6761
  --window <mode> optional \u2014 pane placement: auto, split, or new (default auto)
6751
6762
 
6752
- Output (stdout, bare JSON \u2014 NOT the standard {ok, schema_version, data} envelope)
6763
+ Output (stdout, bare JSON \u2014 NOT the standard {ok, data} envelope)
6753
6764
  { "pane_id": string | null, "reason": string | null }
6754
6765
  pane_id is null when not in tmux or renderer unavailable.
6755
6766
  on error: stderr diagnostic + non-zero exit
@@ -6899,6 +6910,14 @@ function maybeSpawnAskPane(cwd, sessionId, askId, kind) {
6899
6910
  const cmd = `node ${shellQuote(tuiPath)} --cwd ${shellQuote(cwd)} --session-id ${shellQuote(sessionId)} --ask ${shellQuote(askId)}`;
6900
6911
  execSafe(`tmux split-window -d -h -t ${shellQuote(callerPane)} -c ${shellQuote(cwd)} ${shellQuote(cmd)}`);
6901
6912
  }
6913
+ function maybeSpawnReviewPane(cwd, sessionId, askId) {
6914
+ const callerPane = process.env.TMUX_PANE;
6915
+ if (!callerPane) return;
6916
+ if (process.env.SISYPHUS_DISABLE_ASK_PANE === "1") return;
6917
+ const cliPath = join13(import.meta.dirname, "cli.js");
6918
+ const cmd = `node ${shellQuote(cliPath)} ask review open ${shellQuote(askId)} --session ${shellQuote(sessionId)}`;
6919
+ execSafe(`tmux split-window -h -t ${shellQuote(callerPane)} -c ${shellQuote(cwd)} ${shellQuote(cmd)}`);
6920
+ }
6902
6921
  async function submitDeck(deck, opts, options) {
6903
6922
  const blocking = options?.blocking !== false;
6904
6923
  const { cwd, sessionId } = resolveSessionEnv(opts);
@@ -6982,11 +7001,12 @@ async function submitReview(absFile, opts, options) {
6982
7001
  pid: process.pid,
6983
7002
  claudeSessionId,
6984
7003
  cwd,
6985
- title: `Review ${basename3(absFile)}`,
7004
+ title: `Review ${basename4(absFile)}`,
6986
7005
  kind: "review"
6987
7006
  });
6988
7007
  writeReview(cwd, sessionId, askId, { file: absFile });
6989
7008
  if (!blocking) return { askId };
7009
+ maybeSpawnReviewPane(cwd, sessionId, askId);
6990
7010
  const output = await waitForOutput(cwd, sessionId, askId, initialPpid);
6991
7011
  await markAnswered(cwd, sessionId, askId);
6992
7012
  return { askId, output };
@@ -7177,8 +7197,8 @@ function registerKill(program2) {
7177
7197
  Input
7178
7198
  <sessionId> required. Session to kill.
7179
7199
 
7180
- Output (stdout, JSON, schema_version: 1)
7181
- ok, schema_version: 1, data: { sessionId, killedAgents }
7200
+ Output (stdout, JSON)
7201
+ ok, data: { sessionId, killedAgents }
7182
7202
 
7183
7203
  Effects
7184
7204
  Terminates all running agents and stops the session process.
@@ -7203,8 +7223,8 @@ Input
7203
7223
  <sessionId> required. Session to delete.
7204
7224
  --cwd <path> optional. Project directory; defaults to $SISYPHUS_CWD or cwd.
7205
7225
 
7206
- Output (stdout, JSON, schema_version: 1)
7207
- ok, schema_version: 1, data: { sessionId }
7226
+ Output (stdout, JSON)
7227
+ ok, data: { sessionId }
7208
7228
 
7209
7229
  Effects
7210
7230
  Permanently removes state.json, logs, and all pane records for the session.
@@ -7231,7 +7251,7 @@ Input:
7231
7251
  --stdin Read instructions from stdin instead of --message.
7232
7252
 
7233
7253
  Output (stdout, JSON)
7234
- ok, schema_version: 1, data: { sessionId, tmuxSessionName? }
7254
+ ok, data: { sessionId, tmuxSessionName? }
7235
7255
 
7236
7256
  Effects:
7237
7257
  Respawns the orchestrator process; session history is preserved.
@@ -7271,8 +7291,8 @@ function registerContinue(program2) {
7271
7291
  Input
7272
7292
  --session <id> optional. Defaults to $SISYPHUS_SESSION_ID.
7273
7293
 
7274
- Output (stdout, JSON, schema_version: 1)
7275
- ok, schema_version: 1, data: { sessionId }
7294
+ Output (stdout, JSON)
7295
+ ok, data: { sessionId }
7276
7296
 
7277
7297
  Effects
7278
7298
  Clears the session roadmap and resets status to active. History is preserved.
@@ -7305,8 +7325,8 @@ Input
7305
7325
  --report <report> required. Final completion report text.
7306
7326
  --session <id> optional. Defaults to $SISYPHUS_SESSION_ID.
7307
7327
 
7308
- Output (stdout, JSON, schema_version: 1)
7309
- ok, schema_version: 1, data: { sessionId }
7328
+ Output (stdout, JSON)
7329
+ ok, data: { sessionId }
7310
7330
 
7311
7331
  Effects
7312
7332
  Marks the session as completed in daemon state. Orchestrator-only; sub-agents
@@ -7338,10 +7358,10 @@ function registerRollback(program2) {
7338
7358
  `
7339
7359
  Input
7340
7360
  <sessionId> required. Session to roll back.
7341
- --cycle required. Target cycle boundary (positive integer >= 1).
7361
+ --cycle N required. Target cycle boundary (positive integer >= 1).
7342
7362
 
7343
- Output (stdout, JSON, schema_version: 1)
7344
- ok, schema_version: 1, data: { sessionId, restoredToCycle }
7363
+ Output (stdout, JSON)
7364
+ ok, data: { sessionId, restoredToCycle }
7345
7365
 
7346
7366
  Effects
7347
7367
  Restores session state to the specified cycle boundary; discards all later cycle data.
@@ -7373,8 +7393,8 @@ function registerReconnect(program2) {
7373
7393
  Input
7374
7394
  <session-id> required. ID of the orphaned session to reattach.
7375
7395
 
7376
- Output (stdout, JSON, schema_version: 1)
7377
- ok, schema_version: 1, data: { sessionId, tmuxSessionName, tmuxWindowId }
7396
+ Output (stdout, JSON)
7397
+ ok, data: { sessionId, tmuxSessionName, tmuxWindowId }
7378
7398
 
7379
7399
  Effects
7380
7400
  Registers the existing tmux session with the daemon. No orchestrator is spawned and no session state changes.
@@ -7403,8 +7423,8 @@ Input
7403
7423
  --strategy optional. Copy strategy.md from the source session.
7404
7424
  --name <name> optional. Name for the cloned session.
7405
7425
 
7406
- Output (stdout, JSON, schema_version: 1)
7407
- ok, schema_version: 1, data: { sessionId, tmuxSessionName, goal }
7426
+ Output (stdout, JSON)
7427
+ ok, data: { sessionId, tmuxSessionName, goal }
7408
7428
 
7409
7429
  Effects
7410
7430
  Creates a new independent session with its own roadmap, tmux session, and state.
@@ -7451,8 +7471,8 @@ Input
7451
7471
  <task> required. New task/goal string for the session.
7452
7472
  --session <id> optional. Defaults to $SISYPHUS_SESSION_ID.
7453
7473
 
7454
- Output (stdout, JSON, schema_version: 1)
7455
- ok, schema_version: 1, data: { sessionId, task }
7474
+ Output (stdout, JSON)
7475
+ ok, data: { sessionId, task }
7456
7476
 
7457
7477
  Effects
7458
7478
  Overwrites the session's stored task field in daemon state.
@@ -7481,10 +7501,10 @@ function registerSessionEffort(program2) {
7481
7501
  `
7482
7502
  Input
7483
7503
  <sessionId> required. Session to reconfigure.
7484
- --tier required. Effort level: low | medium | high | xhigh.
7504
+ --tier LEVEL required. Effort level: low | medium | high | xhigh.
7485
7505
 
7486
- Output (stdout, JSON, schema_version: 1)
7487
- ok, schema_version: 1, data: { sessionId, effort }
7506
+ Output (stdout, JSON)
7507
+ ok, data: { sessionId, effort }
7488
7508
 
7489
7509
  Effects
7490
7510
  Updates the session's effort tier in daemon state.
@@ -7517,7 +7537,7 @@ Input:
7517
7537
  --state on|off|toggle \u2014 desired dangerous-mode state (default: toggle).
7518
7538
 
7519
7539
  Output (stdout, JSON)
7520
- ok, schema_version: 1, data: { sessionId, enabled, flushed }
7540
+ ok, data: { sessionId, enabled, flushed }
7521
7541
 
7522
7542
  Effects:
7523
7543
  Sets dangerousMode on the session; flushes any pending asks if enabling.
@@ -7747,7 +7767,7 @@ Input
7747
7767
  --cwd <path> optional \u2014 working directory of the session; defaults to process cwd.
7748
7768
 
7749
7769
  Output (stdout, JSON)
7750
- ok, schema_version: 1, data: { sessionId, context }
7770
+ ok, data: { sessionId, context }
7751
7771
 
7752
7772
  Effects
7753
7773
  None. Read-only.
@@ -7784,7 +7804,6 @@ agent spawn: spawn a worker agent. Returns immediately. Reads instruction from s
7784
7804
 
7785
7805
  Input
7786
7806
  stdin required. Task instruction; treated as the agent's prompt.
7787
- Pipe content directly: \`cat task.md | sis agent spawn \u2026\`.
7788
7807
  --stdin optional boolean. Required when running interactively to
7789
7808
  force-read stdin (mirrors \`sis session lifecycle start\`).
7790
7809
  --agent-type TYPE required. Agent template (e.g. sisyphus:debug, devcore:programmer).
@@ -7793,7 +7812,9 @@ Input
7793
7812
  --session ID optional. Defaults to $SISYPHUS_SESSION_ID.
7794
7813
 
7795
7814
  Output (stdout, JSON)
7796
- ok, schema_version: 1, data: { agentId, sessionId, agentType, name }
7815
+ ok, data: { agentId, sessionId, agentType, name, follow_up }
7816
+ follow_up string. Recommended next call: \`sis agent await <agentId>\`
7817
+ to block until the agent reaches a terminal status.
7797
7818
 
7798
7819
  Effects
7799
7820
  Persists an agent record under the session. Spawns a tmux pane running Claude.
@@ -7883,7 +7904,7 @@ Exit codes: 0 ok | 2 usage | 3 not_found (unknown session) | 5 conflict.`
7883
7904
  const response = await sendRequest(request);
7884
7905
  if (!response.ok) exitError(response.error);
7885
7906
  const agentId = response.data?.agentId;
7886
- emitJsonOk({ agentId, sessionId, agentType, name: agentName });
7907
+ emitJsonOk({ agentId, sessionId, agentType, name: agentName, follow_up: `sis agent await ${agentId}` });
7887
7908
  return;
7888
7909
  });
7889
7910
  }
@@ -7901,7 +7922,7 @@ Input
7901
7922
  None.
7902
7923
 
7903
7924
  Output (stdout, JSON)
7904
- ok, schema_version: 1, data: { agentTypes: [{qualifiedName, source, description}, ...] }
7925
+ ok, data: { agentTypes: [{qualifiedName, source, description}, ...] }
7905
7926
  Sorted by qualifiedName ascending. No pagination \u2014 the catalog is bounded.
7906
7927
 
7907
7928
  Effects
@@ -7931,7 +7952,7 @@ Input
7931
7952
  stdin optional. Piped input used as report when --report is omitted.
7932
7953
 
7933
7954
  Output (stdout, JSON)
7934
- ok, schema_version: 1, data: { sessionId, agentId }
7955
+ ok, data: { sessionId, agentId }
7935
7956
 
7936
7957
  Effects
7937
7958
  Persists the report, closes the agent pane, and signals the daemon. The orchestrator
@@ -7990,8 +8011,8 @@ Input
7990
8011
  --session <id> optional. Defaults to $SISYPHUS_SESSION_ID.
7991
8012
  stdin optional. Read when neither --message nor --stdin is given.
7992
8013
 
7993
- Output (stdout, JSON, schema_version: 1)
7994
- ok, schema_version: 1, data: { sessionId, agentId }
8014
+ Output (stdout, JSON)
8015
+ ok, data: { sessionId, agentId }
7995
8016
 
7996
8017
  Effects
7997
8018
  Records an intermediate checkpoint in the orchestrator; the agent keeps running.
@@ -8050,7 +8071,7 @@ Input
8050
8071
  --session <id> optional. Defaults to $SISYPHUS_SESSION_ID.
8051
8072
 
8052
8073
  Output (stdout, JSON)
8053
- ok, schema_version: 1, data: { agentId, sessionId, status, agentName, agentType, reportPath, report }
8074
+ ok, data: { agentId, sessionId, status, agentName, agentType, reportPath, report }
8054
8075
  Warning written to stderr if the report file cannot be read.
8055
8076
 
8056
8077
  Effects
@@ -8099,8 +8120,8 @@ Input
8099
8120
  <agentId> required. Agent to kill (e.g. agent-003).
8100
8121
  --session <id> optional. Defaults to $SISYPHUS_SESSION_ID.
8101
8122
 
8102
- Output (stdout, JSON, schema_version: 1)
8103
- ok, schema_version: 1, data: { sessionId, agentId }
8123
+ Output (stdout, JSON)
8124
+ ok, data: { sessionId, agentId }
8104
8125
 
8105
8126
  Effects
8106
8127
  Sends a kill signal to the agent's tmux pane and marks the agent terminated in daemon state.
@@ -8132,8 +8153,8 @@ Input
8132
8153
  <agentId> required. Agent to restart (e.g. agent-003).
8133
8154
  --session <id> optional. Defaults to $SISYPHUS_SESSION_ID.
8134
8155
 
8135
- Output (stdout, JSON, schema_version: 1)
8136
- ok, schema_version: 1, data: { sessionId, agentId }
8156
+ Output (stdout, JSON)
8157
+ ok, data: { sessionId, agentId }
8137
8158
 
8138
8159
  Effects
8139
8160
  Spawns the agent in a new tmux pane; previous pane is discarded.
@@ -8171,7 +8192,7 @@ Input
8171
8192
  stdin optional. Piped input used as prompt when --prompt is omitted.
8172
8193
 
8173
8194
  Output (stdout, JSON)
8174
- ok, schema_version: 1, data: { sessionId, mode }
8195
+ ok, data: { sessionId, mode }
8175
8196
 
8176
8197
  Effects
8177
8198
  Kills the current orchestrator process; daemon blocks until all running agents submit, then
@@ -8224,8 +8245,8 @@ Input
8224
8245
  --bg <color> required. Background hex color (e.g. #2d2f33).
8225
8246
  --content <tmux> required. tmux format string content.
8226
8247
 
8227
- Output (stdout, JSON, schema_version: 1)
8228
- ok, schema_version: 1, data: { id }
8248
+ Output (stdout, JSON)
8249
+ ok, data: { id }
8229
8250
 
8230
8251
  Effects
8231
8252
  Registers or replaces the named segment in the status bar.
@@ -8261,8 +8282,8 @@ function registerSegmentUnregister(program2) {
8261
8282
  Input
8262
8283
  --id <id> required. Segment identifier to remove.
8263
8284
 
8264
- Output (stdout, JSON, schema_version: 1)
8265
- ok, schema_version: 1, data: { id }
8285
+ Output (stdout, JSON)
8286
+ ok, data: { id }
8266
8287
 
8267
8288
  Effects
8268
8289
  Removes the named segment from the status bar.
@@ -9508,8 +9529,8 @@ Input
9508
9529
  <session-id> required. Session to pause.
9509
9530
  --force optional. Interrupt running orchestrator/agents immediately.
9510
9531
 
9511
- Output (stdout, JSON, schema_version: 1)
9512
- ok, schema_version: 1, data: { sessionId, force, queued }
9532
+ Output (stdout, JSON)
9533
+ ok, data: { sessionId, force, queued }
9513
9534
 
9514
9535
  Effects
9515
9536
  Signals the session to halt at its next quiesce point, leaving it paused in place.
@@ -10044,7 +10065,7 @@ Filing:
10044
10065
  unauthenticated, opens a prefilled GitHub "new issue" URL instead.
10045
10066
 
10046
10067
  Output (stdout, JSON envelope)
10047
- { ok, schema_version: 1, data: { url | issueUrl, filed } }
10068
+ { ok, data: { url | issueUrl, filed } }
10048
10069
 
10049
10070
  Exit codes: 0 ok | 1 filing error | 2 usage`
10050
10071
  ).action(
@@ -11623,12 +11644,13 @@ Input
11623
11644
  --limit <n> optional \u2014 max sessions returned in list mode; default 20
11624
11645
 
11625
11646
  Output (stdout, JSON)
11626
- list mode: { ok, schema_version: 1, data: { sessions: [SessionSummary, ...] } }
11627
- detail mode: { ok, schema_version: 1, data: { session: SessionSummary } }
11628
- events mode: { ok, schema_version: 1, data: { events: [HistoryEvent, ...] } }
11629
- stats mode: { ok, schema_version: 1, data: { total, completed, killed, avgActiveMs, avgEfficiency, ... } }
11630
- on error: { ok: false, schema_version: 1, error: { code, message } }
11631
- All responses carry schema_version: 1.
11647
+ list mode: { ok, data: { sessions: [SessionSummary, ...] } }
11648
+ sessions sorted by startedAt descending (most recent first).
11649
+ detail mode: { ok, data: { session: SessionSummary } }
11650
+ events mode: { ok, data: { events: [HistoryEvent, ...] } }
11651
+ events in chronological append order (oldest first).
11652
+ stats mode: { ok, data: { total, completed, killed, avgActiveMs, avgEfficiency, ... } }
11653
+ on error: { ok: false, error: { code, message } }
11632
11654
 
11633
11655
  Effects
11634
11656
  None. Read-only.
@@ -11664,9 +11686,9 @@ Input
11664
11686
  --cwd <path> optional \u2014 project directory used to resolve the active session; defaults to $SISYPHUS_CWD then process cwd
11665
11687
 
11666
11688
  Output (stdout, JSON)
11667
- { ok, schema_version: 1, data: { sessionId, outputPath } }
11689
+ { ok, data: { sessionId, outputPath } }
11668
11690
  outputPath is the absolute path of the written zip file (typically ~/Downloads/<sessionId>.zip).
11669
- on error: { ok: false, schema_version: 1, error: { code, message } }
11691
+ on error: { ok: false, error: { code, message } }
11670
11692
 
11671
11693
  Effects
11672
11694
  Writes a zip archive to ~/Downloads.
@@ -11725,7 +11747,7 @@ Input
11725
11747
  --cwd <path> project directory override (default: SISYPHUS_CWD env var or cwd).
11726
11748
 
11727
11749
  Output (stdout, JSON envelope)
11728
- { ok, schema_version: 1, data: { sessionId, storageKey } }
11750
+ { ok, data: { sessionId, storageKey } }
11729
11751
 
11730
11752
  Effects
11731
11753
  Exports session to a temporary zip file, POSTs it to the configured upload URL,
@@ -11864,9 +11886,9 @@ Input
11864
11886
  --cwd <path> optional \u2014 working directory for the Claude session; defaults to $SISYPHUS_CWD then process cwd
11865
11887
 
11866
11888
  Output (stdout, JSON)
11867
- { ok, schema_version: 1, data: { tmuxSession, windowId } }
11889
+ { ok, data: { tmuxSession, windowId } }
11868
11890
  tmuxSession is the tmux session name; windowId is the tmux window ID (e.g. @42).
11869
- on error: { ok: false, schema_version: 1, error: { code, message } }
11891
+ on error: { ok: false, error: { code, message } }
11870
11892
 
11871
11893
  Effects
11872
11894
  Creates a new tmux window named "scratch" in the home tmux session.
@@ -11948,10 +11970,10 @@ File resolution (first match wins)
11948
11970
  3. Most recent session with a requirements.json
11949
11971
 
11950
11972
  Output (stdout, JSON)
11951
- --export: { ok, schema_version: 1, data: { path } } \u2014 path is the absolute path of the written requirements.md
11952
- --schema: { ok, schema_version: 1, data: <schema object> }
11953
- --annotated: { ok, schema_version: 1, data: { markdown } } \u2014 markdown is the annotated guide body string
11954
- on error: { ok: false, schema_version: 1, error: { code, message } }
11973
+ --export: { ok, data: { path } } \u2014 path is the absolute path of the written requirements.md
11974
+ --schema: { ok, data: <schema object> }
11975
+ --annotated: { ok, data: { markdown } } \u2014 markdown is the annotated guide body string
11976
+ on error: { ok: false, error: { code, message } }
11955
11977
 
11956
11978
  Effects
11957
11979
  --export: Writes requirements.md alongside the source requirements.json.
@@ -12133,7 +12155,7 @@ var REQUIREMENTS_ANNOTATED = `# requirements.json \u2014 Annotated Writing Guide
12133
12155
  // belongs in design.md (technical) and plan.md (steps).
12134
12156
 
12135
12157
  "version": 1,
12136
- // ^ Always 1. Reserved for future schema versioning.
12158
+ // ^ Always 1.
12137
12159
 
12138
12160
  "lastModified": "2026-04-04T12:00:00Z",
12139
12161
  // ^ ISO 8601 timestamp. Update on each save.
@@ -12362,7 +12384,7 @@ function renderRequirementsMarkdown(json) {
12362
12384
  }
12363
12385
 
12364
12386
  // src/cli/commands/companion.ts
12365
- import { basename as basename6, dirname as dirname11, join as join28 } from "path";
12387
+ import { basename as basename7, dirname as dirname11, join as join28 } from "path";
12366
12388
  import { mkdirSync as mkdirSync15, readFileSync as readFileSync31, writeFileSync as writeFileSync18 } from "fs";
12367
12389
  init_paths();
12368
12390
  init_companion_types();
@@ -12417,7 +12439,7 @@ function renderMemory(state, repo) {
12417
12439
  const ts = formatTimestamp(rec.timestamp);
12418
12440
  const src = `(${rec.source})`.padEnd(7);
12419
12441
  const text = sanitizeForDisplay(rec.text);
12420
- const repoStr = rec.repo !== null ? `[${sanitizeForDisplay(basename6(rec.repo))}]` : "[\u2014]";
12442
+ const repoStr = rec.repo !== null ? `[${sanitizeForDisplay(basename7(rec.repo))}]` : "[\u2014]";
12421
12443
  lines.push(` [${ts}] ${src} ${text} ${repoStr}`);
12422
12444
  }
12423
12445
  } else {
@@ -12565,11 +12587,11 @@ function registerCompanionProfile(companion) {
12565
12587
  companion profile: retrieve the combined companion profile.
12566
12588
 
12567
12589
  Input
12568
- --name optional. Set companion name (persisted on the daemon).
12569
- --badges optional boolean. Include full badge catalog with unlock status in output.
12590
+ --name NAME optional. Set companion name (persisted on the daemon).
12591
+ --badges optional boolean. Include full badge catalog with unlock status in output.
12570
12592
 
12571
12593
  Output (stdout, JSON)
12572
- ok, schema_version: 1, data: { name, level, title, mood, xp, stats, achievements, repos, lastCommentary, badges? }
12594
+ ok, data: { name, level, title, mood, xp, stats, achievements, repos, lastCommentary, badges? }
12573
12595
 
12574
12596
  Effects
12575
12597
  If --name is provided, updates the companion name on the daemon.
@@ -12769,7 +12791,7 @@ Input
12769
12791
  None.
12770
12792
 
12771
12793
  Output (stdout, JSON)
12772
- ok, schema_version: 1, data: { providers: [{ name, status }, ...] }
12794
+ ok, data: { providers: [{ name, status }, ...] }
12773
12795
  Sorted by name ascending. No pagination \u2014 bounded set.
12774
12796
 
12775
12797
  Effects
@@ -13639,7 +13661,7 @@ Tip: enable systemd in /etc/wsl.conf for the recommended daemon setup.`);
13639
13661
  }
13640
13662
  var sessionCounts = null;
13641
13663
  var program = new Command();
13642
- program.name("sis").description("tmux-integrated orchestration daemon for Claude Code").helpOption("--help", "print -h for any node or leaf").version(
13664
+ program.name("sis").description("tmux-integrated orchestration daemon for Claude Code").helpOption("-h, --help", "print -h for any node or leaf").version(
13643
13665
  JSON.parse(
13644
13666
  readFileSync46(join38(dirname16(fileURLToPath6(import.meta.url)), "..", "package.json"), "utf-8")
13645
13667
  ).version,
@@ -13664,11 +13686,11 @@ Exit codes:
13664
13686
  60 transient (retry-safe: daemon down, timeout, lock contention)
13665
13687
 
13666
13688
  Errors:
13667
- {"ok": false, "schema_version": 1,
13689
+ {"ok": false,
13668
13690
  "error": {"code": "<stable-enum>", "kind": "<usage|not_found|ambiguous|conflict|transient|permanent>",
13669
13691
  "message": "...", "received"?: ..., "expected"?: ..., "next"?: "...", "candidates"?: [...]}}
13670
13692
  `);
13671
- if (process.argv.includes("--help") && process.argv.some((a) => a === "session")) {
13693
+ if ((process.argv.includes("--help") || process.argv.includes("-h")) && process.argv.some((a) => a === "session")) {
13672
13694
  try {
13673
13695
  const resp = await rawSend2({ type: "list", cwd: process.cwd(), all: true }, 250);
13674
13696
  if (resp.ok && Array.isArray(resp.data?.sessions)) {