oasis_test_v2 2.2.106 → 2.2.107

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.
Files changed (2) hide show
  1. package/dist/index.js +125 -11
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -43276,7 +43276,7 @@ var require_websocket = __commonJS({
43276
43276
  var http2 = require("http");
43277
43277
  var net = require("net");
43278
43278
  var tls = require("tls");
43279
- var { randomBytes: randomBytes17, createHash: createHash46 } = require("crypto");
43279
+ var { randomBytes: randomBytes17, createHash: createHash47 } = require("crypto");
43280
43280
  var { Duplex, Readable } = require("stream");
43281
43281
  var { URL: URL2 } = require("url");
43282
43282
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -43944,7 +43944,7 @@ var require_websocket = __commonJS({
43944
43944
  abortHandshake(websocket, socket, "Invalid Upgrade header");
43945
43945
  return;
43946
43946
  }
43947
- const digest = createHash46("sha1").update(key2 + GUID).digest("base64");
43947
+ const digest = createHash47("sha1").update(key2 + GUID).digest("base64");
43948
43948
  if (res.headers["sec-websocket-accept"] !== digest) {
43949
43949
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
43950
43950
  return;
@@ -44313,7 +44313,7 @@ var require_websocket_server = __commonJS({
44313
44313
  var EventEmitter = require("events");
44314
44314
  var http2 = require("http");
44315
44315
  var { Duplex } = require("stream");
44316
- var { createHash: createHash46 } = require("crypto");
44316
+ var { createHash: createHash47 } = require("crypto");
44317
44317
  var extension3 = require_extension();
44318
44318
  var PerMessageDeflate2 = require_permessage_deflate();
44319
44319
  var subprotocol2 = require_subprotocol();
@@ -44620,7 +44620,7 @@ var require_websocket_server = __commonJS({
44620
44620
  );
44621
44621
  }
44622
44622
  if (this._state > RUNNING) return abortHandshake(socket, 503);
44623
- const digest = createHash46("sha1").update(key2 + GUID).digest("base64");
44623
+ const digest = createHash47("sha1").update(key2 + GUID).digest("base64");
44624
44624
  const headers = [
44625
44625
  "HTTP/1.1 101 Switching Protocols",
44626
44626
  "Upgrade: websocket",
@@ -220270,6 +220270,9 @@ var init_memory_control_plane_store = __esm({
220270
220270
  /** protected:FileControlPlaneStore 子类 open() 回放快照时直接恢复(密码须持久化)。 */
220271
220271
  accountSecrets = /* @__PURE__ */ new Map();
220272
220272
  // accountId → { passwordHash?, tokenVersion }
220273
+ /** 已登出会话(ADR 0636;protected:文件版子类回放快照时直接恢复——不持久化的话重启即「复活」)。 */
220274
+ revokedSessions = /* @__PURE__ */ new Map();
220275
+ // tokenHash → record
220273
220276
  verificationCodes = /* @__PURE__ */ new Map();
220274
220277
  // email → record(短 TTL,文件版不持久化)
220275
220278
  /** 组织模型三表(protected:文件版子类回放快照时直接恢复)。 */
@@ -220631,6 +220634,15 @@ var init_memory_control_plane_store = __esm({
220631
220634
  this.accountSecrets.set(accountId, { ...cur, tokenVersion: next });
220632
220635
  return next;
220633
220636
  }
220637
+ // —— 已登出会话(ADR 0636)——
220638
+ async revokeSession(rec2) {
220639
+ const cutoff = Date.parse(rec2.revokedAt);
220640
+ for (const [k2, r] of this.revokedSessions) if (Date.parse(r.expiresAt) < cutoff) this.revokedSessions.delete(k2);
220641
+ if (!this.revokedSessions.has(rec2.tokenHash)) this.revokedSessions.set(rec2.tokenHash, { ...rec2 });
220642
+ }
220643
+ async isSessionRevoked(tokenHash) {
220644
+ return this.revokedSessions.has(tokenHash);
220645
+ }
220634
220646
  // —— 邮箱验证码(单邮箱一条 active)——
220635
220647
  async putVerificationCode(rec2) {
220636
220648
  this.verificationCodes.set(rec2.email, { ...rec2 });
@@ -225833,6 +225845,7 @@ var init_control_plane_file_store = __esm({
225833
225845
  "upsertAccount",
225834
225846
  "setAccountPassword",
225835
225847
  "bumpAccountTokenVersion",
225848
+ "revokeSession",
225836
225849
  "upsertDigitalEmployee",
225837
225850
  "patchDigitalEmployee",
225838
225851
  "putAgentCredential",
@@ -225872,6 +225885,7 @@ var init_control_plane_file_store = __esm({
225872
225885
  for (const link of snap.inviteLinks ?? []) await MemoryControlPlaneStore.prototype.createInviteLink.call(store, link);
225873
225886
  for (const a of snap.accounts ?? []) await MemoryControlPlaneStore.prototype.upsertAccount.call(store, a);
225874
225887
  for (const e of snap.accountSecrets ?? []) store.accountSecrets.set(e.accountId, { ...e.secret });
225888
+ for (const r of snap.revokedSessions ?? []) store.revokedSessions.set(r.tokenHash, { ...r });
225875
225889
  for (const e of snap.digitalEmployees ?? []) await MemoryControlPlaneStore.prototype.upsertDigitalEmployee.call(store, e);
225876
225890
  for (const c of snap.agentCredentials ?? []) await MemoryControlPlaneStore.prototype.putAgentCredential.call(store, c);
225877
225891
  for (const b2 of snap.principalBridges ?? []) await MemoryControlPlaneStore.prototype.putPrincipalBridge.call(store, b2);
@@ -225910,6 +225924,8 @@ var init_control_plane_file_store = __esm({
225910
225924
  inviteLinks: [...this.inviteLinks.values()],
225911
225925
  accounts,
225912
225926
  accountSecrets,
225927
+ // 只有按哈希查的读面,直接读 protected map(同 offboardings)。
225928
+ revokedSessions: [...this.revokedSessions.values()],
225913
225929
  digitalEmployees,
225914
225930
  agentCredentials,
225915
225931
  principalBridges,
@@ -230576,6 +230592,12 @@ function verifySession(token2, secret, nowMs) {
230576
230592
  if (typeof claims.exp !== "number" || claims.exp <= nowMs) return null;
230577
230593
  return claims;
230578
230594
  }
230595
+ function sessionTokenHash(token2) {
230596
+ return (0, import_node_crypto54.createHash)("sha256").update(token2).digest("base64url");
230597
+ }
230598
+ function newSessionId() {
230599
+ return (0, import_node_crypto54.randomBytes)(16).toString("base64url");
230600
+ }
230579
230601
  function generateCode() {
230580
230602
  return String((0, import_node_crypto54.randomInt)(0, 1e6)).padStart(6, "0");
230581
230603
  }
@@ -246652,7 +246674,7 @@ function createAuth(opts) {
246652
246674
  const passwordFailures = /* @__PURE__ */ new Map();
246653
246675
  const sessionCookie = (accountId, tokenVersion) => {
246654
246676
  const t = now();
246655
- const jwt = signSession({ sub: accountId, tokenVersion, iat: t, exp: t + sessionTtlMs }, jwtSecret);
246677
+ const jwt = signSession({ sub: accountId, tokenVersion, iat: t, exp: t + sessionTtlMs, jti: newSessionId() }, jwtSecret);
246656
246678
  const attrs = [`${cookieName}=${jwt}`, "Path=/", "HttpOnly", "SameSite=Lax", `Max-Age=${Math.floor(sessionTtlMs / 1e3)}`];
246657
246679
  if (opts.secureCookie) attrs.push("Secure");
246658
246680
  return attrs.join("; ");
@@ -246710,11 +246732,13 @@ function createAuth(opts) {
246710
246732
  await store.deleteVerificationCode(key2);
246711
246733
  return "ok";
246712
246734
  };
246735
+ const sessionToken = (headers) => parseCookies(typeof headers.cookie === "string" ? headers.cookie : void 0)[cookieName];
246713
246736
  const currentAccount = async (headers) => {
246714
- const raw = parseCookies(typeof headers.cookie === "string" ? headers.cookie : void 0)[cookieName];
246737
+ const raw = sessionToken(headers);
246715
246738
  if (!raw) return null;
246716
246739
  const claims = verifySession(raw, jwtSecret, now());
246717
246740
  if (!claims) return null;
246741
+ if (await store.isSessionRevoked(sessionTokenHash(raw))) return null;
246718
246742
  const sec = await store.getAccountSecret(claims.sub);
246719
246743
  if (!sec || sec.tokenVersion !== claims.tokenVersion) return null;
246720
246744
  const account = await store.getAccount(claims.sub);
@@ -246891,6 +246915,21 @@ function createAuth(opts) {
246891
246915
  return { status: 200, body: { ticket, expiresAt: new Date(exp).toISOString() } };
246892
246916
  }
246893
246917
  if (route2 === "logout") {
246918
+ const raw = sessionToken(headers);
246919
+ const claims = raw ? verifySession(raw, jwtSecret, now()) : null;
246920
+ if (raw && claims) {
246921
+ try {
246922
+ await store.revokeSession({
246923
+ tokenHash: sessionTokenHash(raw),
246924
+ accountId: claims.sub,
246925
+ revokedAt: new Date(now()).toISOString(),
246926
+ expiresAt: new Date(claims.exp).toISOString()
246927
+ });
246928
+ } catch (e) {
246929
+ console.error(`[auth] \u767B\u51FA\u540A\u9500\u5931\u8D25 ${claims.sub}: ${e instanceof Error ? e.message : String(e)}`);
246930
+ return { status: 500, body: { error: { code: "LOGOUT_REVOKE_FAILED", message: "\u767B\u51FA\u672A\u5B8C\u6210\uFF0C\u8BF7\u91CD\u8BD5" } }, setCookie: clearCookie() };
246931
+ }
246932
+ }
246894
246933
  return { status: 200, body: { ok: true }, setCookie: clearCookie() };
246895
246934
  }
246896
246935
  return { status: 404, body: { error: { code: "NOT_FOUND", message: pathname } } };
@@ -264917,6 +264956,14 @@ var init_postgres_control_plane = __esm({
264917
264956
  expires_at timestamptz NOT NULL,
264918
264957
  attempts int NOT NULL DEFAULT 0
264919
264958
  )`);
264959
+ await pool.query(`
264960
+ CREATE TABLE IF NOT EXISTS "${s2}".revoked_sessions (
264961
+ token_hash text PRIMARY KEY, -- SHA-256(base64url) of the oasis_auth JWT
264962
+ account_id text NOT NULL,
264963
+ revoked_at timestamptz NOT NULL,
264964
+ expires_at timestamptz NOT NULL -- = \u4EE4\u724C exp\uFF1B\u8FC7\u4E86\u4EE4\u724C\u672C\u6765\u5C31\u9A8C\u4E0D\u8FC7\uFF0C\u884C\u53EF\u5220
264965
+ )`);
264966
+ await pool.query(`CREATE INDEX IF NOT EXISTS revoked_sessions_expires_idx ON "${s2}".revoked_sessions (expires_at)`);
264920
264967
  await pool.query(`ALTER TABLE "${s2}".company_members ADD COLUMN IF NOT EXISTS display_name text`);
264921
264968
  await pool.query(`ALTER TABLE "${s2}".company_members ADD COLUMN IF NOT EXISTS created_at timestamptz`);
264922
264969
  await pool.query(`ALTER TABLE "${s2}".company_members ADD COLUMN IF NOT EXISTS updated_at timestamptz`);
@@ -265807,6 +265854,19 @@ var init_postgres_control_plane = __esm({
265807
265854
  if (r.rowCount === 0) throw new Error(`account not found: ${accountId}`);
265808
265855
  return Number(r.rows[0].token_version);
265809
265856
  }
265857
+ // —— 已登出会话(ADR 0636)——
265858
+ async revokeSession(rec2) {
265859
+ await this.pool.query(`DELETE FROM ${this.s}.revoked_sessions WHERE expires_at < $1`, [rec2.revokedAt]);
265860
+ await this.pool.query(
265861
+ `INSERT INTO ${this.s}.revoked_sessions (token_hash, account_id, revoked_at, expires_at) VALUES ($1,$2,$3,$4)
265862
+ ON CONFLICT (token_hash) DO NOTHING`,
265863
+ [rec2.tokenHash, rec2.accountId, rec2.revokedAt, rec2.expiresAt]
265864
+ );
265865
+ }
265866
+ async isSessionRevoked(tokenHash) {
265867
+ const r = await this.pool.query(`SELECT 1 FROM ${this.s}.revoked_sessions WHERE token_hash = $1`, [tokenHash]);
265868
+ return (r.rowCount ?? 0) > 0;
265869
+ }
265810
265870
  // —— 邮箱验证码(单邮箱一条 active)——
265811
265871
  async putVerificationCode(rec2) {
265812
265872
  await this.pool.query(
@@ -298359,12 +298419,13 @@ var COMMAND_DECLS = {
298359
298419
  // 填(agent 调 = 它绑定的那个真人),命令行不收。开关 OASIS_PERSONAL_TODO=off 时服务端 404。 ——
298360
298420
  todo: {
298361
298421
  group: "\u4E2A\u4EBA\u5F85\u529E",
298362
- usage: "oasis todo <add|list|edit|done|cancel|reopen> ...",
298422
+ usage: "oasis todo <add|list|show|edit|done|cancel|reopen> ...",
298363
298423
  description: "\u4E2A\u4EBA\u5F85\u529E\uFF1A\u66FF\u4F60\u7ED1\u5B9A\u7684\u90A3\u4E2A\u771F\u4EBA\u8BB0\u4E0B\u6709\u622A\u6B62\u65E5\u7684\u4E8B\uFF0C\u5230\u671F\u524D\u4E00\u5929 09:00\u3001\u5F53\u5929 09:00 \u7CFB\u7EDF\u4F1A\u63D0\u9192 TA\uFF08\u8BBE\u4E86\u5F00\u59CB\u65E5\u7684\uFF0C\u5F00\u59CB\u5F53\u5929 09:00 \u4E5F\u63D0\u9192\u4E00\u6B21\uFF09\u3002\u6BCF\u6761\u8F93\u51FA\u7B2C\u4E00\u884C\u662F\u300C\u4ECA\u5929\uFF1AYYYY-MM-DD \u5468X\uFF08\u65F6\u533A\uFF09\u300D\u2014\u2014\u6362\u7B97\u300C\u8FD9\u5468\u4E94\u300D\u300C\u6708\u5E95\u300D\u4E00\u5F8B\u4EE5\u5B83\u4E3A\u51C6\u3002**\u6CA1\u6709 `oasis todo` \u547D\u4EE4\u6267\u884C\u6210\u529F\uFF0C\u5C31\u4E0D\u80FD\u8BF4\u8BB0\u4E0B\u4E86\u3002**",
298364
- subCommands: ["todo add", "todo list", "todo edit", "todo done", "todo cancel", "todo reopen"],
298424
+ subCommands: ["todo add", "todo list", "todo show", "todo edit", "todo done", "todo cancel", "todo reopen"],
298365
298425
  examples: [
298366
298426
  'oasis todo add --title "\u4EA4 Q3 \u590D\u76D8\u62A5\u544A" --note "\u738B\u603B\u8981\uFF0C\u5468\u4F1A\u524D\u8FC7\u4E00\u904D" --due 2026-10-09',
298367
298427
  "oasis todo list",
298428
+ "oasis todo show td_3f9a1c2b",
298368
298429
  'oasis todo edit td_3f9a1c2b --due 2026-10-12 --reason "\u6392\u671F\u8C03\u6574"',
298369
298430
  "oasis todo done td_3f9a1c2b"
298370
298431
  ]
@@ -298389,6 +298450,13 @@ var COMMAND_DECLS = {
298389
298450
  description: "\u5217\u51FA\u5F85\u529E\uFF0C\u6309\u622A\u6B62\u65E5\u6392\u5E8F\uFF0C\u8FC7\u671F\u7684\u6807\u300C\u5DF2\u8FC7\u671F\u300D\uFF1B\u8BBE\u4E86\u5F00\u59CB\u65E5\u7684\u663E\u793A\u300CX \u6708 X \u65E5\u5F00\u59CB \u2192 X \u6708 X \u65E5\u622A\u6B62\u300D\u3002\u9ED8\u8BA4\u53EA\u5217\u672A\u5B8C\u6210\u7684\uFF1B--all \u8FDE\u5DF2\u5B8C\u6210\u3001\u5DF2\u53D6\u6D88\u7684\u4E00\u8D77\u5217\u3002",
298390
298451
  flags: [{ name: "all", desc: "\u8FDE\u5DF2\u5B8C\u6210 / \u5DF2\u53D6\u6D88\u7684\u4E00\u8D77\u5217", boolean: true, own: true }]
298391
298452
  },
298453
+ "todo show": {
298454
+ group: "\u4E2A\u4EBA\u5F85\u529E",
298455
+ usage: "oasis todo show <id>",
298456
+ description: "\u770B\u4E00\u6761\u5F85\u529E\u7684\u5168\u8C8C\uFF1A\u6807\u9898\u3001\u5F00\u59CB \u2192 \u622A\u6B62\u3001\u72B6\u6001\u3001\u5907\u6CE8\u5168\u6587\uFF0C\u4EE5\u53CA\u53D8\u66F4\u8BB0\u5F55\uFF08\u65F6\u95F4\u3001\u8C01\u6539\u7684 / \u7ECF\u624B agent\u3001\u5B57\u6BB5\u3001\u65E7\u503C \u2192 \u65B0\u503C\u3001\u539F\u56E0\uFF0C\u65B0\u7684\u5728\u524D\uFF09\u3002\u6539\u5907\u6CE8\u524D\u5148\u7528\u5B83\u8BFB\u51FA\u5F53\u524D\u5907\u6CE8\u5168\u6587\uFF1B\u7528\u6237\u95EE\u300C\u4E4B\u524D\u5199\u7684\u662F\u4EC0\u4E48\u300D\u4E5F\u67E5\u8FD9\u91CC\u3002",
298457
+ positional: [{ name: "<id>", required: true, desc: "\u5F85\u529E id\uFF08oasis todo list \u7B2C\u4E00\u5217\uFF09" }],
298458
+ examples: ["oasis todo show td_3f9a1c2b"]
298459
+ },
298392
298460
  "todo edit": {
298393
298461
  group: "\u4E2A\u4EBA\u5F85\u529E",
298394
298462
  usage: "oasis todo edit <id> [--title \u2026] [--note \u2026] [--start YYYY-MM-DD|none] [--start-time HH:mm|none] [--due YYYY-MM-DD] [--time HH:mm|none] [--workorder <\u5DE5\u5355 id>|none] [--reason \u2026]",
@@ -299279,7 +299347,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
299279
299347
  }
299280
299348
  }
299281
299349
  }
299282
- var CLI_VERSION = "2.2.106" ? "2.2.106" : "dev";
299350
+ var CLI_VERSION = "2.2.107" ? "2.2.107" : "dev";
299283
299351
  function apiHeaders(token2, company) {
299284
299352
  const headers = {
299285
299353
  authorization: `Bearer ${token2}`,
@@ -301711,6 +301779,52 @@ ${res.warning}`);
301711
301779
  }
301712
301780
  break;
301713
301781
  }
301782
+ if (sub === "show") {
301783
+ const id = idOf();
301784
+ const [one2, day] = await Promise.all([
301785
+ call("GET", todoPath(id)),
301786
+ call("GET", "/api/todos")
301787
+ ]);
301788
+ const t = one2.todo;
301789
+ const statusText = t.status === "done" ? "\u5DF2\u5B8C\u6210" : t.status === "cancelled" ? "\u5DF2\u53D6\u6D88" : t.dueDate < day.today.date ? "\u672A\u5B8C\u6210\uFF08\u5DF2\u8FC7\u671F\uFF09" : "\u672A\u5B8C\u6210";
301790
+ println(day.todayLine);
301791
+ println(`${t.id} ${t.title}`);
301792
+ println(`\u65F6\u95F4\uFF1A${due(t)}`);
301793
+ println(`\u72B6\u6001\uFF1A${statusText}`);
301794
+ if (t.linkedWorkorderId) println(`\u5DE5\u5355\uFF1A${t.linkedWorkorderId}`);
301795
+ println("\u5907\u6CE8\uFF1A");
301796
+ println(t.note ? t.note : "\uFF08\u65E0\uFF09");
301797
+ const FIELD = {
301798
+ created: "\u8BB0\u4E0B",
301799
+ status: "\u72B6\u6001",
301800
+ title: "\u6807\u9898",
301801
+ note: "\u5907\u6CE8",
301802
+ startDate: "\u5F00\u59CB\u65E5",
301803
+ startTime: "\u5F00\u59CB\u65F6\u523B",
301804
+ dueDate: "\u622A\u6B62\u65E5",
301805
+ dueTime: "\u622A\u6B62\u65F6\u523B",
301806
+ linkedWorkorderId: "\u5DE5\u5355"
301807
+ };
301808
+ const STATUS = { open: "\u672A\u5B8C\u6210", done: "\u5DF2\u5B8C\u6210", cancelled: "\u5DF2\u53D6\u6D88" };
301809
+ const val = (field, v2) => v2 === void 0 || v2 === "" ? "\uFF08\u7A7A\uFF09" : field === "status" ? STATUS[v2] ?? v2 : v2;
301810
+ const fmtAt = (iso9) => new Intl.DateTimeFormat("sv-SE", {
301811
+ timeZone: day.today.timeZone,
301812
+ year: "numeric",
301813
+ month: "2-digit",
301814
+ day: "2-digit",
301815
+ hour: "2-digit",
301816
+ minute: "2-digit",
301817
+ hour12: false
301818
+ }).format(new Date(iso9));
301819
+ const changes = [...one2.changes].sort((a, b2) => b2.at.localeCompare(a.at));
301820
+ println(`\u53D8\u66F4\u8BB0\u5F55\uFF08${changes.length} \u6761\uFF0C\u65B0\u7684\u5728\u524D\uFF09\uFF1A`);
301821
+ for (const c of changes) {
301822
+ const who = c.handActorId ? `${c.actorId}\uFF08\u7ECF\u624B ${c.handActorId}\uFF09` : c.actorId;
301823
+ const what = c.field === "created" ? `\u8BB0\u4E0B\uFF1A${c.newValue ?? ""}` : `${FIELD[c.field] ?? c.field}\uFF1A${val(c.field, c.oldValue)} \u2192 ${val(c.field, c.newValue)}`;
301824
+ println(`- ${fmtAt(c.at)} ${who} ${what}${c.reason ? ` \u539F\u56E0\uFF1A${c.reason}` : ""}`);
301825
+ }
301826
+ break;
301827
+ }
301714
301828
  if (sub === "edit") {
301715
301829
  const id = idOf();
301716
301830
  const body2 = {};
@@ -301736,7 +301850,7 @@ ${res.warning}`);
301736
301850
  println(`${sub === "done" ? "\u5DF2\u5B8C\u6210" : sub === "cancel" ? "\u5DF2\u53D6\u6D88" : "\u5DF2\u91CD\u65B0\u6253\u5F00"}\uFF1A${r.todo.title}\uFF0C${due(r.todo)}`);
301737
301851
  break;
301738
301852
  }
301739
- throw new Error("\u7528\u6CD5: oasis todo <add|list|edit|done|cancel|reopen> \u2026\uFF08oasis todo --help \u770B\u8BE6\u60C5\uFF09");
301853
+ throw new Error("\u7528\u6CD5: oasis todo <add|list|show|edit|done|cancel|reopen> \u2026\uFF08oasis todo --help \u770B\u8BE6\u60C5\uFF09");
301740
301854
  }
301741
301855
  case "skill": {
301742
301856
  const sub = positional[0];
@@ -303404,7 +303518,7 @@ function shimScript() {
303404
303518
  }
303405
303519
 
303406
303520
  // src/index.ts
303407
- var PKG_VERSION = true ? "2.2.106" : "dev";
303521
+ var PKG_VERSION = true ? "2.2.107" : "dev";
303408
303522
  var LOCAL_BIN = localBin();
303409
303523
  var NPM_PREFIX = npmPrefix();
303410
303524
  var INSTANCE = DEFAULT_INSTANCE;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test_v2",
3
- "version": "2.2.106",
3
+ "version": "2.2.107",
4
4
  "description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
5
5
  "bin": {
6
6
  "oasis": "./dist/index.js"
@@ -26,6 +26,6 @@
26
26
  "node": ">=20"
27
27
  },
28
28
  "oasisRelease": {
29
- "sourceHead": "f251b7721412da1529673cd12039208906bb0a6e"
29
+ "sourceHead": "180e4e814716f1a7eb4870a1f88cd4d10398d726"
30
30
  }
31
31
  }