@sema-agent/cli 1.0.12 → 1.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@sema-agent/cli",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@sema-agent/cli",
9
- "version": "1.0.12",
9
+ "version": "1.0.13",
10
10
  "license": "BUSL-1.1",
11
11
  "dependencies": {
12
12
  "@sema-agent/sdk": "0.0.53",
@@ -645,9 +645,9 @@
645
645
  }
646
646
  },
647
647
  "node_modules/@sema-agent/registry-core": {
648
- "version": "0.10.13",
649
- "resolved": "https://registry.npmjs.org/@sema-agent/registry-core/-/registry-core-0.10.13.tgz",
650
- "integrity": "sha512-3cYQ3eULB9zqMA2+bRW967NEuQSl+Nd0dmGcNvQ2Un0NFmFlx/6PqiZTDndOwS1zZvdGIovRKJgUk9XN6ZmxiQ==",
648
+ "version": "0.10.14",
649
+ "resolved": "https://registry.npmjs.org/@sema-agent/registry-core/-/registry-core-0.10.14.tgz",
650
+ "integrity": "sha512-6EJe0WmrOrnEY/mITs8FHwCbBy5zcUWzRd1QaOYdEPF5H1DGvv/YcowZ4fR9HTWOpa9l8VI5mJv8gJA4EVxD0w==",
651
651
  "license": "BUSL-1.1",
652
652
  "dependencies": {
653
653
  "zod": "^3.24.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/cli",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "Sema — your own Claude Code-grade coding agent, in the terminal.",
5
5
  "license": "BUSL-1.1",
6
6
  "bin": {
@@ -26,9 +26,9 @@
26
26
  },
27
27
  "overrides": {
28
28
  "@sema-agent/core": "1.309.0",
29
- "@sema-agent/registry-core": "0.10.13"
29
+ "@sema-agent/registry-core": "0.10.14"
30
30
  },
31
- "semaEngineVersion": "server 1.218.0 / core 1.309.0 / registry-core 0.10.13",
31
+ "semaEngineVersion": "server 1.218.0 / core 1.309.0 / registry-core 0.10.14",
32
32
  "engines": {
33
33
  "node": ">=18"
34
34
  }
package/sema.js CHANGED
@@ -359913,6 +359913,15 @@ function genericResultText(r, opts) {
359913
359913
  return typeof bb?.text === "string" ? bb.text : bb?.type === "image" ? "[image]" : "";
359914
359914
  }).filter(Boolean).join("\n");
359915
359915
  }
359916
+ if (s.trimStart().startsWith("[")) {
359917
+ try {
359918
+ const arr = JSON.parse(s);
359919
+ if (Array.isArray(arr) && arr.length > 0 && arr.every((b3) => b3 && typeof b3 === "object" && (b3.type === "text" || b3.type === "image"))) {
359920
+ s = arr.map((bb) => typeof bb.text === "string" ? bb.text : bb.type === "image" ? "[image]" : "").filter(Boolean).join("\n");
359921
+ }
359922
+ } catch {
359923
+ }
359924
+ }
359916
359925
  s = s.trimEnd();
359917
359926
  if (!s) return "";
359918
359927
  if (opts?.full) return s;
@@ -359967,7 +359976,7 @@ function UserToolSuccessMessage({
359967
359976
  if (report) {
359968
359977
  renderedMessage = /* @__PURE__ */ (0, import_jsx_runtime118.jsx)(SubagentReportSummary, { report, isTranscriptMode });
359969
359978
  } else {
359970
- const fallbackText = genericResultText(message.toolUseResult);
359979
+ const fallbackText = genericResultText(message.toolUseResult, { full: Boolean(isTranscriptMode) || verbose });
359971
359980
  if (fallbackText) renderedMessage = /* @__PURE__ */ (0, import_jsx_runtime118.jsx)(MessageResponse, { children: /* @__PURE__ */ (0, import_jsx_runtime118.jsx)(ThemedText, { children: fallbackText }) });
359972
359981
  }
359973
359982
  }
@@ -406129,7 +406138,10 @@ var init_lifetimeMarkers = __esm({
406129
406138
 
406130
406139
  // build-src/src/tools/ScheduleCronTool/UI.tsx
406131
406140
  function renderCreateToolUseMessage(input) {
406132
- return `${input.cron ?? ""}${input.prompt ? `: ${truncate(input.prompt, 60, true)}` : ""}`;
406141
+ const s = input.schedule;
406142
+ const sched = input.cron ?? (s?.kind === "cron" && typeof s.expr === "string" ? s.expr : s?.kind === "delay" && typeof s.delaySec === "number" ? `in ${s.delaySec}s` : s?.kind === "at" ? `at ${typeof s.at === "string" ? s.at : "\u2026"}` : void 0);
406143
+ const label = input.label ? ` [${input.label}]` : "";
406144
+ return `${sched ?? ""}${label}${input.prompt ? `: ${truncate(input.prompt, 60, true)}` : ""}`;
406133
406145
  }
406134
406146
  function renderCreateResultMessage(output) {
406135
406147
  return /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(MessageResponse, { children: /* @__PURE__ */ (0, import_jsx_runtime154.jsxs)(ThemedText, { children: [
@@ -406203,10 +406215,17 @@ var init_CronCreateTool = __esm({
406203
406215
  init_UI24();
406204
406216
  MAX_JOBS = 50;
406205
406217
  inputSchema35 = lazySchema(
406206
- () => external_exports.strictObject({
406207
- cron: external_exports.string().describe(
406218
+ () => external_exports.object({
406219
+ cron: external_exports.string().optional().describe(
406208
406220
  'Standard 5-field cron expression in local time: "M H DoM Mon DoW" (e.g. "*/5 * * * *" = every 5 minutes, "30 14 28 2 *" = Feb 28 at 2:30pm local once).'
406209
406221
  ),
406222
+ schedule: external_exports.object({
406223
+ kind: external_exports.string().optional(),
406224
+ expr: external_exports.string().optional(),
406225
+ delaySec: external_exports.number().optional(),
406226
+ at: external_exports.string().optional()
406227
+ }).optional().describe("Engine schedule form (kinds cron/at/delay) \u2014 accepted by the live engine tool face."),
406228
+ label: external_exports.string().optional(),
406210
406229
  prompt: external_exports.string().describe("The prompt to enqueue at each fire time."),
406211
406230
  recurring: semanticBoolean(external_exports.boolean().optional()).describe(
406212
406231
  `true (default) = fire on every cron match until deleted or auto-expired after ${DEFAULT_MAX_AGE_DAYS} days. false = fire once at the next match, then auto-delete. Use false for "remind me at X" one-shot requests with pinned minute/hour/dom/month.`
@@ -406251,6 +406270,13 @@ var init_CronCreateTool = __esm({
406251
406270
  return getCronFilePath();
406252
406271
  },
406253
406272
  async validateInput(input) {
406273
+ if (typeof input.cron !== "string" || input.cron.length === 0) {
406274
+ return {
406275
+ result: false,
406276
+ message: "This local CronCreate accepts the 5-field `cron` string form. The `schedule` object form is handled by the live engine tool \u2014 pass `cron` here.",
406277
+ errorCode: 5
406278
+ };
406279
+ }
406254
406280
  if (!parseCronExpression(input.cron)) {
406255
406281
  return {
406256
406282
  result: false,
@@ -426077,7 +426103,7 @@ var init_BashTool = __esm({
426077
426103
  init_toolName();
426078
426104
  init_UI();
426079
426105
  init_utils6();
426080
- import_jsx_runtime163 = __toESM(require_jsx_runtime());
426106
+ import_jsx_runtime163 = __toESM(require_jsx_runtime(), 1);
426081
426107
  EOL5 = "\n";
426082
426108
  PROGRESS_THRESHOLD_MS3 = 2e3;
426083
426109
  ASSISTANT_BLOCKING_BUDGET_MS2 = 15e3;
@@ -479492,8 +479518,8 @@ var init_sema_brand = __esm({
479492
479518
  "Slash-command gating wired to the fleet capability handshake"
479493
479519
  ]
479494
479520
  },
479495
- productVersion: "1.0.12",
479496
- announcement: "sema 1.0.12 \u2014 background-process and wakeup lifetimes are now honest (tool descriptions say what survives the session; headless wakeup scheduling is refused where it can never fire), finalize no longer triggers early on long-thinking first turns, and scheduler upsert keys stop colliding across sessions"
479521
+ productVersion: "1.0.13",
479522
+ announcement: "sema 1.0.13 \u2014 tool cards render faithfully again (CronCreate headers, skill results, full output behind ctrl+o), and scheduler writes are concurrency-safe across sessions and daemons"
479497
479523
  };
479498
479524
  }
479499
479525
  });
@@ -482427,8 +482453,8 @@ var require_sema_brand = __commonJS({
482427
482453
  "Slash-command gating wired to the fleet capability handshake"
482428
482454
  ]
482429
482455
  },
482430
- productVersion: "1.0.12",
482431
- announcement: "sema 1.0.12 \u2014 background-process and wakeup lifetimes are now honest (tool descriptions say what survives the session; headless wakeup scheduling is refused where it can never fire), finalize no longer triggers early on long-thinking first turns, and scheduler upsert keys stop colliding across sessions"
482456
+ productVersion: "1.0.13",
482457
+ announcement: "sema 1.0.13 \u2014 tool cards render faithfully again (CronCreate headers, skill results, full output behind ctrl+o), and scheduler writes are concurrency-safe across sessions and daemons"
482432
482458
  };
482433
482459
  }
482434
482460
  });
@@ -496964,6 +496990,7 @@ var init_types19 = __esm({
496964
496990
  maxTokens: external_exports3.number().int().positive().optional(),
496965
496991
  autoCompactTokens: external_exports3.number().int().positive().optional(),
496966
496992
  charsPerToken: external_exports3.number().finite().positive().optional(),
496993
+ promptGuidance: external_exports3.array(external_exports3.string()).optional(),
496967
496994
  cost: ModelCost.optional(),
496968
496995
  extraBody: external_exports3.unknown().optional().transform((v2, ctx) => {
496969
496996
  if (v2 === void 0)
@@ -607537,8 +607564,8 @@ function _temp161() {
607537
607564
  var import_compiler_runtime316, import_react313, SETTINGS_ERRORS_NOTIFICATION_KEY;
607538
607565
  var init_useSettingsErrors = __esm({
607539
607566
  "build-src/src/hooks/notifs/useSettingsErrors.tsx"() {
607540
- import_compiler_runtime316 = __toESM(require_compiler_runtime());
607541
- import_react313 = __toESM(require_react());
607567
+ import_compiler_runtime316 = __toESM(require_compiler_runtime(), 1);
607568
+ import_react313 = __toESM(require_react(), 1);
607542
607569
  init_notifications();
607543
607570
  init_state();
607544
607571
  init_allErrors();
@@ -640407,6 +640434,7 @@ async function ensurePrintModeEngine() {
640407
640434
  }
640408
640435
  async function ensureLocalEngineOneShot(label = "one-shot") {
640409
640436
  seedUserSettingsEnv();
640437
+ process.env.SCHEDULER_SESSION_WAKEUP ??= "false";
640410
640438
  try {
640411
640439
  const { applyPersistedTlsTrust: applyPersistedTlsTrust2 } = await Promise.resolve().then(() => (init_tlsTrust(), tlsTrust_exports));
640412
640440
  await applyPersistedTlsTrust2();
@@ -653659,7 +653687,7 @@ Auth: unix socket -R \u2192 local proxy`, "info");
653659
653687
  pendingHookMessages
653660
653688
  }, renderAndRun);
653661
653689
  }
653662
- }).version("sema 1.0.12", "-v, --version", "Output the version number");
653690
+ }).version("sema 1.0.13", "-v, --version", "Output the version number");
653663
653691
  program2.option("-w, --worktree [name]", "Create a new git worktree for this session (optionally specify a name)");
653664
653692
  program2.option("--tmux", "Create a tmux session for the worktree (requires --worktree). Uses iTerm2 native panes when available; use --tmux=classic for traditional tmux.");
653665
653693
  if (canUserConfigureAdvisor()) {
@@ -657423,19 +657451,29 @@ var init_schedulerDaemon = __esm({
657423
657451
  /** Run one tick: fire due intents, persist the rescheduled/reaped record set. Returns the count fired. */
657424
657452
  async tickOnce() {
657425
657453
  const nowMs = (this.opts.now ?? (() => Date.now()))();
657426
- let all4;
657427
- try {
657428
- all4 = this.store.load();
657429
- } catch (e) {
657430
- this.opts.onError?.(e);
657431
- return 0;
657432
- }
657433
- const owned = [];
657434
- const foreign = [];
657435
- for (const r of all4) (this.opts.owns?.(r) ?? true ? owned : foreign).push(r);
657436
- const { toFire, updated } = tickRecords(owned, nowMs);
657454
+ let toFire = [];
657455
+ const computeNext = (all4) => {
657456
+ const owned = [];
657457
+ const foreign = [];
657458
+ for (const r of all4) (this.opts.owns?.(r) ?? true ? owned : foreign).push(r);
657459
+ const t2 = tickRecords(owned, nowMs);
657460
+ toFire = t2.toFire;
657461
+ if (t2.toFire.length === 0 && t2.updated.length === owned.length && t2.updated.every((r, i) => r === owned[i])) return null;
657462
+ return [...t2.updated, ...foreign];
657463
+ };
657437
657464
  try {
657438
- this.store.save([...updated, ...foreign]);
657465
+ if (this.store.mutate) {
657466
+ const m2 = this.store.mutate(computeNext);
657467
+ if (!m2.ok && m2.reason !== "aborted") {
657468
+ this.opts.onError?.(new Error(`scheduler store mutate failed: ${m2.reason}`));
657469
+ return 0;
657470
+ }
657471
+ if (!m2.ok) return 0;
657472
+ } else {
657473
+ const next = computeNext(this.store.load());
657474
+ if (next === null) return 0;
657475
+ this.store.save(next);
657476
+ }
657439
657477
  } catch (e) {
657440
657478
  this.opts.onError?.(e);
657441
657479
  return 0;
@@ -657529,6 +657567,30 @@ function saveSchedulerStore(path27, records) {
657529
657567
  writeFileSync21(tmp, serializeSchedulerStore(records), { mode: 384 });
657530
657568
  renameSync10(tmp, path27);
657531
657569
  }
657570
+ function mutateSchedulerStore(path27, fn2, opts) {
657571
+ const maxRetries = Math.max(0, opts?.retries ?? 5);
657572
+ const rawOf = () => {
657573
+ try {
657574
+ return readFileSync51(path27, "utf-8");
657575
+ } catch {
657576
+ return null;
657577
+ }
657578
+ };
657579
+ for (let attempt = 0; ; attempt++) {
657580
+ const baseRaw = rawOf();
657581
+ const records = baseRaw === null ? [] : parseSchedulerStore(baseRaw);
657582
+ const next = fn2(records);
657583
+ if (next === null)
657584
+ return { ok: false, reason: "aborted" };
657585
+ if (rawOf() !== baseRaw) {
657586
+ if (attempt >= maxRetries)
657587
+ return { ok: false, reason: "conflict_exhausted", retries: attempt };
657588
+ continue;
657589
+ }
657590
+ saveSchedulerStore(path27, next);
657591
+ return { ok: true, records: next, retries: attempt };
657592
+ }
657593
+ }
657532
657594
  var init_scheduler_store_node = __esm({
657533
657595
  "node_modules/@sema-agent/registry-core/dist/scheduler-store-node.js"() {
657534
657596
  init_scheduler_store();
@@ -657570,7 +657632,9 @@ function schedulerStorePath() {
657570
657632
  function fileSchedulerStoreIO(storePath) {
657571
657633
  return {
657572
657634
  load: () => loadSchedulerStore(storePath),
657573
- save: (records) => saveSchedulerStore(storePath, records)
657635
+ save: (records) => saveSchedulerStore(storePath, records),
657636
+ // [1003] 唯一跨进程变更原语绑定:daemon tick/sessionReap/孤儿清扫的写路径全走它。
657637
+ mutate: (fn2) => mutateSchedulerStore(storePath, fn2)
657574
657638
  };
657575
657639
  }
657576
657640
  var init_schedulerDaemonWire = __esm({
@@ -657599,6 +657663,15 @@ function partitionSessionReap(records, departedSessionIds) {
657599
657663
  }
657600
657664
  function reapSessionRecords(io, departedSessionIds) {
657601
657665
  if (departedSessionIds.length === 0) return [];
657666
+ if (io.mutate) {
657667
+ let ids = [];
657668
+ const m2 = io.mutate((records) => {
657669
+ const { kept: kept2, reaped: reaped2 } = partitionSessionReap(records, departedSessionIds);
657670
+ ids = reaped2.map((r) => r.id);
657671
+ return reaped2.length === 0 ? null : kept2;
657672
+ });
657673
+ return m2.ok || !m2.ok && m2.reason === "aborted" ? ids : [];
657674
+ }
657602
657675
  const { kept, reaped } = partitionSessionReap(io.load(), departedSessionIds);
657603
657676
  if (reaped.length === 0) return [];
657604
657677
  io.save(kept);
@@ -657677,13 +657750,26 @@ function sweepOrphanSessionRecords(io, storePath, opts = {}) {
657677
657750
  cleanupDead: true
657678
657751
  });
657679
657752
  for (const id of opts.ownSessionIds ?? []) if (id) claimed.add(id);
657680
- const kept = [];
657681
- const reapedIds = [];
657682
- for (const r of records) {
657683
- const orphan = isSessionLifetimeRecord(r) && typeof r.sessionId === "string" && r.sessionId.length > 0 && !claimed.has(r.sessionId) && nowMs - r.createdMs > graceMs;
657684
- if (orphan) reapedIds.push(r.id);
657685
- else kept.push(r);
657686
- }
657753
+ const partition3 = (all4) => {
657754
+ const kept2 = [];
657755
+ const reapedIds2 = [];
657756
+ for (const r of all4) {
657757
+ const orphan = isSessionLifetimeRecord(r) && typeof r.sessionId === "string" && r.sessionId.length > 0 && !claimed.has(r.sessionId) && nowMs - r.createdMs > graceMs;
657758
+ if (orphan) reapedIds2.push(r.id);
657759
+ else kept2.push(r);
657760
+ }
657761
+ return { kept: kept2, reapedIds: reapedIds2 };
657762
+ };
657763
+ if (io.mutate) {
657764
+ let ids = [];
657765
+ const m2 = io.mutate((all4) => {
657766
+ const t2 = partition3(all4);
657767
+ ids = t2.reapedIds;
657768
+ return t2.reapedIds.length === 0 ? null : t2.kept;
657769
+ });
657770
+ return m2.ok || !m2.ok && m2.reason === "aborted" ? ids : [];
657771
+ }
657772
+ const { kept, reapedIds } = partition3(records);
657687
657773
  if (reapedIds.length > 0) io.save(kept);
657688
657774
  return reapedIds;
657689
657775
  }