oasis_test 0.1.84 → 0.1.85

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 +277 -69
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -138754,6 +138754,16 @@ function nodeLabel(a) {
138754
138754
  const tail = a.id.split(":").slice(2).join(":");
138755
138755
  return tail ? `\u672A\u547D\u540D ${a.type}\uFF08${tail}\uFF09` : `\u672A\u547D\u540D ${a.type}`;
138756
138756
  }
138757
+ function workspaceTitleMap(model) {
138758
+ const titleOf = /* @__PURE__ */ new Map();
138759
+ for (const a of model.artifacts.values()) {
138760
+ if (a.type === "brief") {
138761
+ const title = a.title ?? a.description;
138762
+ if (title) titleOf.set(a.workspace, title);
138763
+ }
138764
+ }
138765
+ return titleOf;
138766
+ }
138757
138767
  function isCurrentHeadConcluded2(model, a) {
138758
138768
  return a.currentRev !== null && concludedHead(model, a.id) === a.currentRev;
138759
138769
  }
@@ -141042,6 +141052,56 @@ var init_session_creds = __esm({
141042
141052
  }
141043
141053
  });
141044
141054
 
141055
+ // ../connectors/src/_base/refresh.ts
141056
+ function isExpiringSoon(expiresAtMs, nowMs, skewMs = CREDENTIAL_REFRESH_SKEW_MS) {
141057
+ if (!expiresAtMs) return true;
141058
+ return nowMs >= expiresAtMs - skewMs;
141059
+ }
141060
+ async function refreshCredentialsIfNeeded(connector, credentials, opts = {}) {
141061
+ if (!connector.refreshCredentials) {
141062
+ return { status: "unsupported", detail: `${connector.config.slug}: \u51ED\u636E\u4E0D\u8FC7\u671F\uFF0C\u65E0\u9700\u7EED\u671F` };
141063
+ }
141064
+ const nowMs = opts.nowMs ?? Date.now();
141065
+ const skewMs = opts.skewMs ?? CREDENTIAL_REFRESH_SKEW_MS;
141066
+ const expiresAt = readEpochMs(credentials, connector.expiresAtCredentialKey);
141067
+ if (!isExpiringSoon(expiresAt, nowMs, skewMs)) {
141068
+ return { status: "fresh" };
141069
+ }
141070
+ const materialExpiresAt = readEpochMs(credentials, connector.refreshMaterialExpiresAtCredentialKey);
141071
+ if (materialExpiresAt && nowMs >= materialExpiresAt) {
141072
+ return { status: "expired", detail: `${connector.config.slug}: \u7EED\u671F\u6750\u6599\u5DF2\u8FC7\u671F\uFF0C\u9700\u91CD\u65B0\u6388\u6743` };
141073
+ }
141074
+ try {
141075
+ const result = await connector.refreshCredentials(credentials);
141076
+ if (!result) return { status: "not-refreshable", detail: `${connector.config.slug}: \u65E0\u53EF\u7528\u7EED\u671F\u6750\u6599` };
141077
+ return {
141078
+ status: "refreshed",
141079
+ credentials: result.credentials,
141080
+ ...result.expiresAt ? { expiresAt: result.expiresAt } : {}
141081
+ };
141082
+ } catch (err) {
141083
+ return { status: "failed", detail: summarize(err) };
141084
+ }
141085
+ }
141086
+ function readEpochMs(credentials, key) {
141087
+ if (!key) return void 0;
141088
+ const raw = credentials[key];
141089
+ if (!raw) return void 0;
141090
+ const n = Number(raw);
141091
+ return Number.isFinite(n) && n > 0 ? n : void 0;
141092
+ }
141093
+ function summarize(err) {
141094
+ const e = err;
141095
+ return (typeof e?.message === "string" ? e.message : String(err)).slice(0, 300);
141096
+ }
141097
+ var CREDENTIAL_REFRESH_SKEW_MS;
141098
+ var init_refresh = __esm({
141099
+ "../connectors/src/_base/refresh.ts"() {
141100
+ "use strict";
141101
+ CREDENTIAL_REFRESH_SKEW_MS = 5 * 60 * 1e3;
141102
+ }
141103
+ });
141104
+
141045
141105
  // ../connectors/src/_base/cli-connector.ts
141046
141106
  function summarizeError(err) {
141047
141107
  const e = err;
@@ -141184,13 +141244,32 @@ var init_base = __esm({
141184
141244
  init_tool_home();
141185
141245
  init_wrapper_assets();
141186
141246
  init_session_creds();
141247
+ init_refresh();
141187
141248
  init_cli_connector();
141188
141249
  init_mcp_connector();
141189
141250
  }
141190
141251
  });
141191
141252
 
141192
141253
  // ../connectors/src/feishu/index.ts
141193
- var import_node_child_process7, import_node_util4, import_node_path6, import_node_url2, import_promises3, execFileAsync2, __dirname2, FEISHU_WELL_KNOWN_SKILLS_BASE, FeishuConnector;
141254
+ function parseFeishuTokenResponse(data, nowMs) {
141255
+ const accessToken = String(data["access_token"] ?? "");
141256
+ const refreshToken = String(data["refresh_token"] ?? "");
141257
+ const expiresInSec = Number(data["expires_in"] ?? 7200);
141258
+ const refreshExpiresInSec = Number(
141259
+ data["refresh_token_expires_in"] ?? data["refresh_expires_in"] ?? 30 * 24 * 3600
141260
+ );
141261
+ const expiresAtMs = nowMs + expiresInSec * 1e3;
141262
+ return {
141263
+ credentials: {
141264
+ ...accessToken ? { user_access_token: accessToken } : {},
141265
+ ...refreshToken ? { refresh_token: refreshToken } : {},
141266
+ user_token_expires_at: String(expiresAtMs),
141267
+ refresh_token_expires_at: String(nowMs + refreshExpiresInSec * 1e3)
141268
+ },
141269
+ expiresAt: new Date(expiresAtMs)
141270
+ };
141271
+ }
141272
+ var import_node_child_process7, import_node_util4, import_node_path6, import_node_url2, import_promises3, execFileAsync2, __dirname2, FEISHU_WELL_KNOWN_SKILLS_BASE, FEISHU_TOKEN_URL, FeishuConnector;
141194
141273
  var init_feishu = __esm({
141195
141274
  "../connectors/src/feishu/index.ts"() {
141196
141275
  "use strict";
@@ -141203,6 +141282,7 @@ var init_feishu = __esm({
141203
141282
  execFileAsync2 = (0, import_node_util4.promisify)(import_node_child_process7.execFile);
141204
141283
  __dirname2 = (0, import_node_path6.dirname)((0, import_node_url2.fileURLToPath)(__esm_import_meta_url));
141205
141284
  FEISHU_WELL_KNOWN_SKILLS_BASE = "https://open.feishu.cn/.well-known/skills";
141285
+ FEISHU_TOKEN_URL = "https://open.feishu.cn/open-apis/authen/v2/oauth/token";
141206
141286
  FeishuConnector = class extends CliConnector {
141207
141287
  config = {
141208
141288
  slug: "feishu",
@@ -141220,12 +141300,28 @@ var init_feishu = __esm({
141220
141300
  commandName = "lark-cli";
141221
141301
  requiredCommands = ["lark-cli"];
141222
141302
  envPrefix = "FEISHU_";
141223
- /** server 侧从 actor 变量表组装凭据的声明(见 provision.ts)。 */
141303
+ /** server 侧从 actor 变量表组装凭据的声明(见 provision.ts)。这些会随 job 下发到节点。 */
141224
141304
  credentialSources = [
141225
141305
  { key: "app_id", from: "FEISHU_APP_ID", required: true },
141226
141306
  { key: "app_secret", from: "FEISHU_APP_SECRET", required: true },
141227
141307
  { key: "user_access_token", from: "FEISHU_USER_ACCESS_TOKEN", required: false }
141228
141308
  ];
141309
+ /**
141310
+ * 续期材料——**只在 server 侧读,不下发节点**。refresh_token 能换出新的 user token,
141311
+ * 属于"长期材料",没有任何理由让它出现在 agent 所在的机器上。
141312
+ */
141313
+ refreshCredentialSources = [
141314
+ { key: "app_id", from: "FEISHU_APP_ID", required: true },
141315
+ { key: "app_secret", from: "FEISHU_APP_SECRET", required: true },
141316
+ { key: "refresh_token", from: "FEISHU_REFRESH_TOKEN", required: true },
141317
+ { key: "user_token_expires_at", from: "FEISHU_USER_TOKEN_EXPIRES_AT", required: false },
141318
+ { key: "refresh_token_expires_at", from: "FEISHU_REFRESH_TOKEN_EXPIRES_AT", required: false },
141319
+ { key: "user_access_token", from: "FEISHU_USER_ACCESS_TOKEN", required: false }
141320
+ ];
141321
+ /** 过期判定只认这个键——必须与注入时消费的 token 同源(见接口注释里的历史坑)。 */
141322
+ expiresAtCredentialKey = "user_token_expires_at";
141323
+ /** refresh_token 自身 ~30d 过期,过了只能重新授权。 */
141324
+ refreshMaterialExpiresAtCredentialKey = "refresh_token_expires_at";
141229
141325
  /**
141230
141326
  * 绝不允许进入 agent 进程环境的原始变量。
141231
141327
  * 含 APP_ID 与几个过期时间戳:它们本身不算密钥,但同属飞书凭据材料,一并挡在 agent 之外,
@@ -141316,6 +141412,36 @@ var init_feishu = __esm({
141316
141412
  sessionEnv.set("FEISHU_RUN_TMPDIR", creds.dir);
141317
141413
  sessionEnv.set("LARKSUITE_CLI_CONFIG_DIR", configDir);
141318
141414
  }
141415
+ /**
141416
+ * 用 refresh_token 换一对新的 user token(飞书 v2 OAuth)。
141417
+ *
141418
+ * **纯换取,不落库**——持久化由调用方做(server 侧 `oauth.ts`)。这样平台知识
141419
+ * (端点、字段名、~2h/~30d 的寿命)全部收在连接器里,与 GitHub App 的续期共用
141420
+ * `_base/refresh.ts` 那套判定。
141421
+ *
141422
+ * 返回 null=没有可用的续期材料(未完成授权)。平台报错则抛,由上层收敛成 failed。
141423
+ */
141424
+ async refreshCredentials(credentials) {
141425
+ const appId = credentials["app_id"];
141426
+ const appSecret = credentials["app_secret"];
141427
+ const refreshToken = credentials["refresh_token"];
141428
+ if (!appId || !appSecret || !refreshToken) return null;
141429
+ const resp = await fetch(FEISHU_TOKEN_URL, {
141430
+ method: "POST",
141431
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
141432
+ body: new URLSearchParams({
141433
+ grant_type: "refresh_token",
141434
+ refresh_token: refreshToken,
141435
+ client_id: appId,
141436
+ client_secret: appSecret
141437
+ }).toString()
141438
+ });
141439
+ const data = await resp.json();
141440
+ if (!resp.ok || data["error"]) {
141441
+ throw new Error(`feishu refresh failed: HTTP ${resp.status} ${String(data["error"] ?? "")}`.trim());
141442
+ }
141443
+ return parseFeishuTokenResponse(data, Date.now());
141444
+ }
141319
141445
  async initNewApp() {
141320
141446
  await new Promise((resolve9, reject) => {
141321
141447
  const proc = (0, import_node_child_process7.spawn)(this.larkBin, ["config", "init", "--new"], { stdio: "inherit" });
@@ -141526,52 +141652,54 @@ var init_scopes = __esm({
141526
141652
 
141527
141653
  // ../connectors/src/feishu/oauth.ts
141528
141654
  async function persistFeishuUserTokens(store, actorId, data, nowMs) {
141529
- const accessToken = String(data["access_token"] ?? "");
141530
- const refreshToken = String(data["refresh_token"] ?? "");
141531
- const expiresInSec = Number(data["expires_in"] ?? 7200);
141532
- const refreshExpiresInSec = Number(data["refresh_token_expires_in"] ?? data["refresh_expires_in"] ?? 30 * 24 * 3600);
141533
- const put = (key, value2, encrypted) => store.putVariable({ key, value: value2, scope: "personal", actorId, connectorId: "feishu", encrypted });
141534
- if (accessToken) await put("FEISHU_USER_ACCESS_TOKEN", accessToken, true);
141535
- if (refreshToken) await put("FEISHU_REFRESH_TOKEN", refreshToken, true);
141536
- await put("FEISHU_USER_TOKEN_EXPIRES_AT", String(nowMs + expiresInSec * 1e3), false);
141537
- await put("FEISHU_REFRESH_TOKEN_EXPIRES_AT", String(nowMs + refreshExpiresInSec * 1e3), false);
141655
+ const { credentials } = parseFeishuTokenResponse(data, nowMs);
141656
+ await persistRefreshedCredentials(store, actorId, credentials);
141657
+ }
141658
+ async function persistRefreshedCredentials(store, actorId, credentials) {
141659
+ const connector = new FeishuConnector();
141660
+ const secretKeys = new Set(connector.config.schema.filter((f2) => f2.secret).map((f2) => f2.key));
141661
+ for (const src of connector.refreshCredentialSources ?? []) {
141662
+ const value2 = credentials[src.key];
141663
+ if (value2 === void 0) continue;
141664
+ await store.putVariable({
141665
+ key: src.from,
141666
+ value: value2,
141667
+ scope: "personal",
141668
+ actorId,
141669
+ connectorId: "feishu",
141670
+ encrypted: secretKeys.has(src.key)
141671
+ });
141672
+ }
141538
141673
  }
141539
141674
  async function refreshFeishuUserTokenIfNeeded(store, actorId) {
141540
- const expiresAt = Number(await store.revealVariable("FEISHU_USER_TOKEN_EXPIRES_AT", actorId) ?? 0);
141541
- const nowMs = Date.now();
141542
- if (expiresAt && nowMs < expiresAt - REFRESH_SKEW_MS) return;
141543
- const refreshToken = await store.revealVariable("FEISHU_REFRESH_TOKEN", actorId);
141544
- const appId = await store.revealResolvedVariable("FEISHU_APP_ID", actorId);
141545
- const appSecret = await store.revealResolvedVariable("FEISHU_APP_SECRET", actorId);
141546
- if (!refreshToken || !appId || !appSecret) return;
141547
- const refreshExpiresAt = Number(await store.revealVariable("FEISHU_REFRESH_TOKEN_EXPIRES_AT", actorId) ?? 0);
141548
- if (refreshExpiresAt && nowMs >= refreshExpiresAt) {
141549
- await store.deleteVariable("FEISHU_USER_ACCESS_TOKEN", actorId);
141550
- await store.deleteVariable("FEISHU_REFRESH_TOKEN", actorId);
141551
- await store.deleteVariable("FEISHU_USER_TOKEN_EXPIRES_AT", actorId);
141552
- await store.deleteVariable("FEISHU_REFRESH_TOKEN_EXPIRES_AT", actorId);
141675
+ const connector = new FeishuConnector();
141676
+ const credentials = {};
141677
+ for (const src of connector.refreshCredentialSources ?? []) {
141678
+ const v2 = src.key === "app_id" || src.key === "app_secret" ? await store.revealResolvedVariable(src.from, actorId) : await store.revealVariable(src.from, actorId);
141679
+ if (v2) credentials[src.key] = v2;
141680
+ }
141681
+ const outcome = await refreshCredentialsIfNeeded(connector, credentials);
141682
+ if (outcome.status === "refreshed" && outcome.credentials) {
141683
+ await persistRefreshedCredentials(store, actorId, outcome.credentials);
141684
+ return;
141685
+ }
141686
+ if (outcome.status === "expired") {
141687
+ for (const key of [
141688
+ "FEISHU_USER_ACCESS_TOKEN",
141689
+ "FEISHU_REFRESH_TOKEN",
141690
+ "FEISHU_USER_TOKEN_EXPIRES_AT",
141691
+ "FEISHU_REFRESH_TOKEN_EXPIRES_AT"
141692
+ ]) {
141693
+ await store.deleteVariable(key, actorId);
141694
+ }
141553
141695
  return;
141554
141696
  }
141555
- const resp = await fetch(FEISHU_TOKEN_URL, {
141556
- method: "POST",
141557
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
141558
- body: new URLSearchParams({
141559
- grant_type: "refresh_token",
141560
- refresh_token: refreshToken,
141561
- client_id: appId,
141562
- client_secret: appSecret
141563
- }).toString()
141564
- });
141565
- const data = await resp.json();
141566
- if (!resp.ok || data["error"]) return;
141567
- await persistFeishuUserTokens(store, actorId, data, nowMs);
141568
141697
  }
141569
- var FEISHU_TOKEN_URL, REFRESH_SKEW_MS;
141570
141698
  var init_oauth = __esm({
141571
141699
  "../connectors/src/feishu/oauth.ts"() {
141572
141700
  "use strict";
141573
- FEISHU_TOKEN_URL = "https://open.feishu.cn/open-apis/authen/v2/oauth/token";
141574
- REFRESH_SKEW_MS = 5 * 60 * 1e3;
141701
+ init_refresh();
141702
+ init_feishu();
141575
141703
  }
141576
141704
  });
141577
141705
 
@@ -146518,6 +146646,7 @@ var init_src5 = __esm({
146518
146646
  init_base();
146519
146647
  init_base();
146520
146648
  init_base();
146649
+ init_base();
146521
146650
  init_feishu();
146522
146651
  init_scopes();
146523
146652
  init_oauth();
@@ -151023,6 +151152,7 @@ var init_memory_control_plane_store = __esm({
151023
151152
  else c.avatar = patch.avatar;
151024
151153
  }
151025
151154
  if (patch.status !== void 0) c.status = patch.status;
151155
+ if (patch.onboardingVariant !== void 0) c.onboardingVariant = patch.onboardingVariant;
151026
151156
  this.companies.set(id, c);
151027
151157
  }
151028
151158
  // —— 成员 ——
@@ -157804,7 +157934,7 @@ function clip(text2) {
157804
157934
  const s2 = typeof text2 === "string" ? text2.trim() : "";
157805
157935
  return s2.length > CLIP ? `${s2.slice(0, CLIP)}\u2026` : s2;
157806
157936
  }
157807
- function summarize(kind, payload) {
157937
+ function summarize2(kind, payload) {
157808
157938
  const p2 = payload;
157809
157939
  switch (kind) {
157810
157940
  case "report_gap":
@@ -157853,7 +157983,7 @@ async function actorActivity(oplog, actorId, limit = 50) {
157853
157983
  for await (const { op } of oplog.readAll()) {
157854
157984
  if (op.actor !== actorId) continue;
157855
157985
  total++;
157856
- matched.push({ at: op.timestamp, kind: op.kind, target: op.target, ...summarize(op.kind, op.payload) });
157986
+ matched.push({ at: op.timestamp, kind: op.kind, target: op.target, ...summarize2(op.kind, op.payload) });
157857
157987
  if (matched.length > capped) matched.shift();
157858
157988
  }
157859
157989
  matched.reverse();
@@ -159068,7 +159198,11 @@ function toApiError(e) {
159068
159198
  const code = e.code;
159069
159199
  const message = e instanceof Error ? e.message : String(e);
159070
159200
  if (code === "FORBIDDEN") throw new ApiError(403, code, message);
159071
- if (code === "ASSISTANT_LAZY_CREATE_FAILED") throw new ApiError(409, code, message);
159201
+ if (code === "ASSISTANT_LAZY_CREATE_FAILED") {
159202
+ const step = e.step;
159203
+ if (step === "no-runtime" || step === "probe-failed") throw new ApiError(503, "ASSISTANT_SERVICE_UNAVAILABLE", message);
159204
+ throw new ApiError(409, code, message);
159205
+ }
159072
159206
  if (code === "AUTO_ASSIGN_OFF") throw new ApiError(409, code, message);
159073
159207
  if (code === "ASSISTANT_ARCHIVED_CANNOT_REACTIVATE") throw new ApiError(409, code, message);
159074
159208
  if (code === "LEGACY_AGENT_NOT_ELIGIBLE_FOR_REBIND") throw new ApiError(409, code, message);
@@ -160136,6 +160270,31 @@ var init_service4 = __esm({
160136
160270
  async get(id) {
160137
160271
  return this.store.getCompany(id);
160138
160272
  }
160273
+ /**
160274
+ * 读取公司的登录后助理引导变体(首个 per-company 配置字段)。
160275
+ * 缺省/未设一律视为 "A"(默认);**读取失败绝不抛给调用方**——降级到 "A",
160276
+ * 保证登录后引导流程永远有一个确定的默认路径,不因控制面读故障而阻塞。
160277
+ */
160278
+ async getOnboardingVariant(companyId) {
160279
+ try {
160280
+ const c = await this.store.getCompany(companyId);
160281
+ return c?.onboardingVariant ?? "A";
160282
+ } catch {
160283
+ return "A";
160284
+ }
160285
+ }
160286
+ /**
160287
+ * 设置公司的登录后助理引导变体("A" | "B")。公司不存在则抛 404,非法值抛 400。
160288
+ * 权限(owner/admin)由路由层强制。
160289
+ */
160290
+ async setOnboardingVariant(companyId, variant) {
160291
+ if (variant !== "A" && variant !== "B") {
160292
+ throw new CompanyError(400, "BAD_REQUEST", `onboardingVariant \u987B\u4E3A "A" | "B"`);
160293
+ }
160294
+ const company = await this.requireCompany(companyId);
160295
+ await this.store.updateCompany(companyId, { onboardingVariant: variant });
160296
+ return { ...company, onboardingVariant: variant };
160297
+ }
160139
160298
  /** 设置/清除公司头像引用("blob:<哈希>";null = 回到默认首字母标识)。 */
160140
160299
  async setAvatar(id, ref2) {
160141
160300
  const company = await this.requireCompany(id);
@@ -160472,6 +160631,13 @@ function companiesDomain(opts) {
160472
160631
  throw e;
160473
160632
  };
160474
160633
  const whoami = (req) => currentUser(req.auth, req.raw.headers);
160634
+ const requireOwnerOrAdmin = async (req, companyId) => {
160635
+ const me = await whoami(req);
160636
+ const member = await service.getMember(companyId, me.accountId);
160637
+ if (!member || member.role !== "owner" && member.role !== "admin") {
160638
+ throw new ApiError(403, "FORBIDDEN", "\u9700\u8981\u8BE5\u516C\u53F8\u7684 owner/admin \u6743\u9650");
160639
+ }
160640
+ };
160475
160641
  return (router) => {
160476
160642
  router.get("/api/companies", async (req) => {
160477
160643
  const me = await whoami(req);
@@ -160483,6 +160649,19 @@ function companiesDomain(opts) {
160483
160649
  if (!company) throw new ApiError(404, "NOT_FOUND", `\u6CA1\u6709\u8FD9\u4E2A\u516C\u53F8\uFF1A${req.params.id}`);
160484
160650
  return { status: 200, body: company };
160485
160651
  });
160652
+ router.patch("/api/companies/:id", async (req) => {
160653
+ const cid = req.params.id;
160654
+ const b2 = req.body ?? {};
160655
+ if (b2.onboardingVariant === void 0) {
160656
+ throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11\u53EF\u66F4\u65B0\u5B57\u6BB5\uFF08onboardingVariant\uFF09");
160657
+ }
160658
+ if (b2.onboardingVariant !== "A" && b2.onboardingVariant !== "B") {
160659
+ throw new ApiError(400, "BAD_REQUEST", `onboardingVariant \u987B\u4E3A "A" | "B"`);
160660
+ }
160661
+ await requireOwnerOrAdmin(req, cid);
160662
+ const company = await service.setOnboardingVariant(cid, b2.onboardingVariant).catch(mapErr);
160663
+ return { status: 200, body: company };
160664
+ });
160486
160665
  router.post("/api/companies", async (req) => {
160487
160666
  const b2 = req.body ?? {};
160488
160667
  const me = await whoami(req);
@@ -162047,14 +162226,10 @@ function buildInbox(model, me, leadOf, resolveActor, markers = [], slaMs, nowIso
162047
162226
  const downstreamCount = (id) => consumersOf(model, id).length;
162048
162227
  const firstSentence = (s2, max = 80) => (s2 ?? "").replace(/\s+/g, " ").trim().slice(0, max);
162049
162228
  const creatorOf = /* @__PURE__ */ new Map();
162050
- const titleOf = /* @__PURE__ */ new Map();
162051
162229
  for (const a of model.artifacts.values()) {
162052
- if (a.type === "brief") {
162053
- creatorOf.set(a.workspace, a.owner);
162054
- const title = a.title ?? a.description;
162055
- if (title) titleOf.set(a.workspace, title);
162056
- }
162230
+ if (a.type === "brief") creatorOf.set(a.workspace, a.owner);
162057
162231
  }
162232
+ const titleOf = workspaceTitleMap(model);
162058
162233
  const staffingSeen = /* @__PURE__ */ new Set();
162059
162234
  for (const a of model.artifacts.values()) {
162060
162235
  if (!isPendingOwner(a.owner) || creatorOf.get(a.workspace) !== me) continue;
@@ -162445,8 +162620,20 @@ function toAuditEntry(op) {
162445
162620
  summary: `${KIND_LABEL[op.kind] ?? op.kind} \xB7 ${op.artifactId}`
162446
162621
  };
162447
162622
  }
162448
- async function buildAudit(oplog, q = {}) {
162623
+ function enrichAudit(entry, model, titleOf) {
162624
+ const a = model.artifacts.get(entry.artifactId);
162625
+ if (!a) return { ...entry, visibility: "deleted" };
162626
+ const workspaceTitle = titleOf.get(a.workspace);
162627
+ return {
162628
+ ...entry,
162629
+ nodeName: nodeLabel(a),
162630
+ ...workspaceTitle ? { workspaceTitle } : {},
162631
+ visibility: "ok"
162632
+ };
162633
+ }
162634
+ async function buildAudit(oplog, q = {}, model) {
162449
162635
  const limit = Math.min(Math.max(q.limit ?? 100, 1), 500);
162636
+ const titleOf = model ? workspaceTitleMap(model) : void 0;
162450
162637
  const items = [];
162451
162638
  let lastCursor = null;
162452
162639
  let truncated = false;
@@ -162456,7 +162643,8 @@ async function buildAudit(oplog, q = {}) {
162456
162643
  if (q.kind && op.kind !== q.kind) continue;
162457
162644
  if (q.from && op.timestamp < q.from) continue;
162458
162645
  if (q.to && op.timestamp > q.to) continue;
162459
- items.push(toAuditEntry(op));
162646
+ const base = toAuditEntry(op);
162647
+ items.push(model && titleOf ? enrichAudit(base, model, titleOf) : base);
162460
162648
  lastCursor = cursor;
162461
162649
  if (items.length >= limit) {
162462
162650
  truncated = true;
@@ -162469,6 +162657,7 @@ var KIND_LABEL;
162469
162657
  var init_audit = __esm({
162470
162658
  "../server/src/domains/collab/audit.ts"() {
162471
162659
  "use strict";
162660
+ init_node_state();
162472
162661
  KIND_LABEL = {
162473
162662
  spawn_artifact: "\u5EFA\u4EA7\u7269",
162474
162663
  propose_revision: "\u63D0\u4FEE\u8BA2",
@@ -163457,7 +163646,7 @@ function collabDomain(opts) {
163457
163646
  return { status: 200, body: { ok: true } };
163458
163647
  });
163459
163648
  router.get("/api/audit", async (req) => {
163460
- const { oplog } = await resolveCtx(req.auth.companyId);
163649
+ const { oplog, kernel } = await resolveCtx(req.auth.companyId);
163461
163650
  const q = req.query;
163462
163651
  const audit = {};
163463
163652
  const actor = q.get("actor");
@@ -163472,7 +163661,7 @@ function collabDomain(opts) {
163472
163661
  if (cursor) audit.cursor = cursor;
163473
163662
  const limit = q.get("limit");
163474
163663
  if (limit) audit.limit = Number(limit);
163475
- return { status: 200, body: await buildAudit(oplog, audit) };
163664
+ return { status: 200, body: await buildAudit(oplog, audit, kernel.model) };
163476
163665
  });
163477
163666
  router.get("/api/dashboard", async (req) => {
163478
163667
  const { kernel, oplog, registry: registry2 } = await resolveCtx(req.auth.companyId);
@@ -165643,7 +165832,7 @@ function validateTriggers(raw) {
165643
165832
  }
165644
165833
  function automationsDomain(opts) {
165645
165834
  const { service } = opts;
165646
- const summarize2 = async (id) => {
165835
+ const summarize3 = async (id) => {
165647
165836
  const automation = await service.getAutomation(id);
165648
165837
  if (!automation) return null;
165649
165838
  const [triggers, recent] = await Promise.all([
@@ -165668,7 +165857,7 @@ function automationsDomain(opts) {
165668
165857
  return { status: 200, body };
165669
165858
  });
165670
165859
  router.get("/api/automations/:id", async (req) => {
165671
- const summary = await summarize2(req.params.id);
165860
+ const summary = await summarize3(req.params.id);
165672
165861
  if (!summary) throw new ApiError(404, "NOT_FOUND", `\u6CA1\u6709\u8FD9\u4E2A\u81EA\u52A8\u5316\uFF1A${req.params.id}`);
165673
165862
  return { status: 200, body: summary };
165674
165863
  });
@@ -165698,7 +165887,7 @@ function automationsDomain(opts) {
165698
165887
  ...b2.createdBy !== void 0 ? { createdBy: b2.createdBy } : {},
165699
165888
  ...triggers !== void 0 ? { triggers } : {}
165700
165889
  });
165701
- const summary = await summarize2(created.id);
165890
+ const summary = await summarize3(created.id);
165702
165891
  return { status: 201, body: summary };
165703
165892
  });
165704
165893
  router.patch("/api/automations/:id", async (req) => {
@@ -165717,7 +165906,7 @@ function automationsDomain(opts) {
165717
165906
  ...b2.enabled !== void 0 ? { enabled: b2.enabled } : {},
165718
165907
  ...triggers !== void 0 ? { triggers } : {}
165719
165908
  });
165720
- const summary = await summarize2(id);
165909
+ const summary = await summarize3(id);
165721
165910
  return { status: 200, body: summary };
165722
165911
  });
165723
165912
  router.post("/api/automations/:id/enabled", async (req) => {
@@ -165726,7 +165915,7 @@ function automationsDomain(opts) {
165726
165915
  const b2 = req.body ?? {};
165727
165916
  if (typeof b2.enabled !== "boolean") throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11 enabled\uFF08boolean\uFF09");
165728
165917
  await service.setEnabled(id, b2.enabled);
165729
- const summary = await summarize2(id);
165918
+ const summary = await summarize3(id);
165730
165919
  return { status: 200, body: summary };
165731
165920
  });
165732
165921
  router.post("/api/automations/:id/run-now", async (req) => {
@@ -174895,7 +175084,9 @@ var init_registry3 = __esm({
174895
175084
  dependsOn: ["diagnosis:\u6839\u56E0\u5206\u6790"],
174896
175085
  role: "\u5F00\u53D1",
174897
175086
  ownerRole: "dev",
174898
- brief: () => `\u6309\u300C\u6839\u56E0\u5206\u6790\u300D\u7ED9\u51FA\u7684\u65B9\u6848\u4FEE\u590D\u5E76\u4EA4\u4ED8\u4EE3\u7801\u3002\u6539\u52A8\u805A\u7126\u6839\u56E0\u3001\u907F\u514D\u8FC7\u5EA6\u6269\u6563\uFF1B\u81EA\u6D4B\u8986\u76D6\u5DE5\u5355\u63CF\u8FF0\u91CC\u6240\u62A5\u7684\u90A3\u6761\u8DEF\u5F84\u3002`
175087
+ brief: () => `**\u4EA7\u51FA**\uFF1A\u6309\u300C\u6839\u56E0\u5206\u6790\u300D\u7ED9\u51FA\u7684\u65B9\u6848\u4FEE\u590D\u5E76\u4EA4\u4ED8\u4EE3\u7801\u3002
175088
+ **\u8D1F\u8D23\u5230\u54EA**\uFF1A\u53EA\u6539\u6839\u56E0\u6D89\u53CA\u7684\u90E8\u5206\uFF0C\u907F\u514D\u8FC7\u5EA6\u6269\u6563\uFF1B\u4E0A\u7EBF\u4E0E\u9A8C\u8BC1\u5F52\u4E0B\u6E38\u3002
175089
+ **\u4EA4\u4ED8\u524D\u5FC5\u987B\u80FD\u56DE\u7B54**\uFF1A\u2460 \u5DE5\u5355\u63CF\u8FF0\u91CC\u6240\u62A5\u7684\u90A3\u6761\u8DEF\u5F84\uFF0C\u81EA\u6D4B\u8DD1\u901A\u4E86\u5417\u3001\u600E\u4E48\u8DD1\u7684\uFF1F\u2461 \u672C\u6B21\u65B0\u5F15\u5165\u6216\u6539\u5199\u7684\u5224\u65AD\uFF0C\u5728\u5B83\u7684\u6BCF\u4E00\u79CD\u72B6\u6001\u4E0B\u7ED3\u8BBA\u5206\u522B\u662F\u4EC0\u4E48\uFF1F\u2462 \u8BCA\u65AD\u91CC\u7684\u65B9\u6848\u6709\u6CA1\u6709\u54EA\u6761\u4F60\u6CA1\u7167\u505A\u3001\u4E3A\u4EC0\u4E48\uFF1F`
174899
175090
  },
174900
175091
  {
174901
175092
  // 修复与冒烟之间必须隔一道上线核验:dev 收尾的**同一刻**下游就解除阻塞,而那时合并才刚发生、
@@ -174906,7 +175097,9 @@ var init_registry3 = __esm({
174906
175097
  dependsOn: ["dev:\u4FEE\u590D\u5B9E\u73B0"],
174907
175098
  role: "\u8FD0\u7EF4\u90E8\u7F72",
174908
175099
  ownerRole: "devops",
174909
- brief: () => `\u786E\u8BA4\u300C\u4FEE\u590D\u5B9E\u73B0\u300D\u4EA4\u4ED8\u7684\u90A3\u4E2A commit **\u771F\u7684\u8DD1\u5230\u4E86\u76EE\u6807\u73AF\u5883\u4E0A**\uFF0C\u7136\u540E\u653E\u884C\u4E0B\u6E38\u5192\u70DF\u3002
175100
+ brief: () => `**\u4EA7\u51FA**\uFF1A\u4E00\u4EFD\u90E8\u7F72\u8BB0\u5F55\uFF0C\u786E\u8BA4\u300C\u4FEE\u590D\u5B9E\u73B0\u300D\u4EA4\u4ED8\u7684\u90A3\u4E2A commit **\u771F\u7684\u8DD1\u5230\u4E86\u76EE\u6807\u73AF\u5883\u4E0A**\uFF0C\u7136\u540E\u653E\u884C\u4E0B\u6E38\u5192\u70DF\u3002
175101
+ **\u8D1F\u8D23\u5230\u54EA**\uFF1A\u53EA\u786E\u8BA4\u300C\u4E0A\u6CA1\u4E0A\u53BB\u300D\uFF0C\u4E0D\u5224\u65AD\u529F\u80FD\u5BF9\u9519\u2014\u2014\u90A3\u662F\u5192\u70DF\u7684\u4E8B\u3002
175102
+ **\u4EA4\u4ED8\u524D\u5FC5\u987B\u80FD\u56DE\u7B54**\uFF1A\u2460 \u4E0A\u7EBF\u7684\u662F\u54EA\u4E2A commit\uFF1F\u2461 \u4E0B\u6E38\u8981\u9A8C\u7684\u662F\u54EA\u4E2A\u73AF\u5883\u5730\u5740\uFF08\u5192\u70DF\u5168\u9760\u8FD9\u6761\u77E5\u9053\u53BB\u54EA\u6D4B\uFF09\uFF1F\u2462 \u63A2\u9488\u5B9E\u9645\u8FD4\u56DE\u4E86\u4EC0\u4E48\uFF1F
174910
175103
 
174911
175104
  **\u5224\u636E\u4E24\u6761\uFF0C\u7F3A\u4E00\u4E0D\u53EF**\uFF1A
174912
175105
  \u2460 \u90E8\u7F72\u6D41\u6C34\u7EBF\u5728\u8BE5 commit \u4E0A\u7684\u8FD0\u884C\u7ED3\u8BBA\u4E3A success\uFF1B
@@ -174916,8 +175109,6 @@ var init_registry3 = __esm({
174916
175109
 
174917
175110
  **\u4F60\u63A5\u5230\u8FD9\u4E2A\u4EFB\u52A1\u65F6\uFF0C\u90E8\u7F72\u516B\u6210\u8FD8\u6CA1\u5B8C\u6210**\uFF08\u5408\u5E76\u5230\u4E0A\u7EBF\u8981\u51E0\u5206\u949F\uFF09\u3002\u505A\u6CD5\uFF1A**\u5728\u540C\u4E00\u4E2A\u56DE\u5408\u91CC\u8F6E\u8BE2\u7740\u7B49**\u2014\u2014\u67E5\u4E00\u6B21\u3001\`sleep\` \u4E00\u4F1A\u513F\u3001\u518D\u67E5\u3002\u6BCF\u8F6E\u628A\u89C2\u5BDF\u5230\u7684\u5199\u4E0B\u6765\uFF08\u7B2C\u51E0\u6B21\u67E5\u3001\u6D41\u6C34\u7EBF\u4EC0\u4E48\u72B6\u6001\u3001\u63A2\u9488\u62A5\u7684\u662F\u54EA\u4E2A sha\uFF09\uFF0C\u8BA9\u4EBA\u5728\u8F68\u8FF9\u91CC\u770B\u5F97\u89C1\u4F60\u5728\u7B49\u4EC0\u4E48\u3002**\u7EDD\u4E0D\u8981\u7ED3\u675F\u56DE\u5408\u53BB\u7B49\u5524\u9192**\uFF08\u90A3\u7C7B\u5DE5\u5177\u5728\u8FD9\u91CC\u5FC5\u6B7B\uFF0C\u4F1A\u53D8\u6210\u96F6\u4EA7\u51FA\u4F1A\u8BDD\uFF09\u3002\u7B49\u5230\u4E0A\u9650\uFF08\u5EFA\u8BAE 10 \u5206\u949F\uFF09\u4ECD\u4E0D\u5230\u4F4D\uFF0C\u5C31**\u5982\u5B9E\u4E0A\u62A5\u7B49\u4E0D\u5230\u3001\u8BF4\u660E\u5361\u5728\u54EA\u4E00\u6B65**\uFF0C\u4E0D\u8BB8\u5047\u88C5\u901A\u8FC7\u3002
174918
175111
 
174919
- **\u4EA7\u51FA\u90E8\u7F72\u8BB0\u5F55**\uFF0C\u5FC5\u987B\u5305\u542B\uFF1A\u4E0A\u7EBF\u7684\u662F\u54EA\u4E2A commit\u3001**\u4E0B\u6E38\u8981\u9A8C\u7684\u662F\u54EA\u4E2A\u73AF\u5883\u5730\u5740**\uFF08\u5192\u70DF\u5168\u9760\u8FD9\u6761\u77E5\u9053\u53BB\u54EA\u6D4B\uFF09\u3001\u63A2\u9488\u5B9E\u9645\u8FD4\u56DE\u4E86\u4EC0\u4E48\u3002
174920
-
174921
175112
  **\u4F60\u8BF4\u901A\u8FC7\u4E0D\u7B97\u6570**\u2014\u2014\u6536\u5C3E\u65F6\u673A\u5668\u4F1A\u62FF\u540C\u6837\u7684\u5224\u636E\u5B9E\u6D4B\u590D\u6838\u4E00\u904D\uFF0C\u5BF9\u4E0D\u4E0A\u4F1A\u6253\u56DE\u3002\u6240\u4EE5\u522B\u53EA\u8BFB\u4EE3\u7801\u5C31\u5224\u5B9A\uFF0C\u4E5F\u522B\u5728\u63A2\u9488\u6253\u4E0D\u901A\u65F6\u731C\u300C\u5E94\u8BE5\u597D\u4E86\u300D\u3002\u82E5\u67E5\u660E\u662F\u73AF\u5883/\u6D41\u6C34\u7EBF\u95EE\u9898\u800C\u4E0D\u662F\u4EE3\u7801\u95EE\u9898\uFF0C\u5982\u5B9E\u4E0A\u62A5\u5347\u7EA7\uFF0C**\u4E0D\u8981\u6253\u56DE\u4E0A\u6E38\u7684\u300C\u4FEE\u590D\u5B9E\u73B0\u300D**\u2014\u2014\u8BA9\u5F00\u53D1\u91CD\u5199\u4EE3\u7801\u89E3\u51B3\u4E0D\u4E86\u90E8\u7F72\u73AF\u5883\u7684\u95EE\u9898\u3002`
174922
175113
  },
174923
175114
  {
@@ -174928,7 +175119,15 @@ var init_registry3 = __esm({
174928
175119
  dependsOn: ["cd:\u4E0A\u7EBF\u6838\u9A8C"],
174929
175120
  role: "\u5192\u70DF\u6D4B\u8BD5",
174930
175121
  ownerRole: "smoke",
174931
- brief: () => `\u7167\u5DE5\u5355\u63CF\u8FF0\u91CC\u6240\u62A5\u7684\u73B0\u8C61\u5728\u771F\u5B9E\u73AF\u5883\u8D70\u4E00\u904D\uFF0C\u786E\u8BA4\u5B83\u786E\u5B9E\u4E0D\u518D\u51FA\u73B0\uFF1B\u987A\u5E26\u786E\u8BA4\u6539\u52A8\u6CA1\u6709\u660E\u663E\u6253\u574F\u76F4\u63A5\u76F8\u90BB\u7684\u8DEF\u5F84\u3002**\u4E0D\u505A\u5168\u91CF\u56DE\u5F52\u3001\u4E0D\u5199\u6D4B\u8BD5\u8BA1\u5212**\u3002\u4EA7\u51FA\u9A8C\u8BC1\u8BB0\u5F55\uFF1A\u6267\u884C\u4E86\u54EA\u4E9B\u547D\u4EE4\u3001\u770B\u5230\u4EC0\u4E48\u8F93\u51FA\u3001\u636E\u6B64\u5224\u5B9A\u901A\u8FC7\u4E0E\u5426\u3002\u5224\u636E\u6765\u81EA\u5DE5\u5355\u63CF\u8FF0\u672C\u8EAB\u2014\u2014\u6CA1\u6709\u771F\u5B9E\u6267\u884C\u8FC7\u4E0D\u7B97\u9A8C\u8BC1\u8FC7\u3002**\u63CF\u8FF0\u91CC\u6CA1\u6709\u53EF\u6267\u884C\u7684\u590D\u73B0\u65B9\u5F0F\u65F6\uFF0C\u5148\u5982\u5B9E\u8BF4\u660E\u8FD9\u4E00\u70B9\uFF0C\u518D\u7ED9\u51FA\u4F60\u5B9E\u9645\u91C7\u7528\u7684\u9A8C\u8BC1\u65B9\u5F0F**\uFF0C\u4E0D\u8981\u56E0\u4E3A\u300C\u4EE3\u7801\u770B\u8D77\u6765\u5BF9\u300D\u5C31\u5224\u901A\u8FC7\u3002\u9A8C\u4E0D\u8FC7\u5982\u5B9E\u6253\u56DE\u300C\u4FEE\u590D\u5B9E\u73B0\u300D\u5E76\u5199\u6E05\u5361\u5728\u54EA\u4E00\u6B65\u3001\u5B9E\u9645\u770B\u5230\u4EC0\u4E48\u3002`,
175122
+ brief: () => `**\u4EA7\u51FA**\uFF1A\u4E00\u4EFD\u9A8C\u8BC1\u8BB0\u5F55\u2014\u2014\u7167\u5DE5\u5355\u63CF\u8FF0\u91CC\u6240\u62A5\u7684\u73B0\u8C61\u5728\u771F\u5B9E\u73AF\u5883\u8D70\u4E00\u904D\uFF0C\u786E\u8BA4\u5B83\u786E\u5B9E\u4E0D\u518D\u51FA\u73B0\u3002
175123
+ **\u8D1F\u8D23\u5230\u54EA**\uFF1A\u53EA\u9A8C\u6240\u62A5\u73B0\u8C61 + \u76F4\u63A5\u76F8\u90BB\u7684\u8DEF\u5F84\u6709\u6CA1\u6709\u88AB\u6253\u574F\uFF1B**\u4E0D\u505A\u5168\u91CF\u56DE\u5F52\u3001\u4E0D\u5199\u6D4B\u8BD5\u8BA1\u5212**\u3002
175124
+ **\u4EA4\u4ED8\u524D\u5FC5\u987B\u80FD\u56DE\u7B54**\uFF1A\u2460 \u6BCF\u6761\u9A8C\u6536\u6807\u51C6\u4F60\u5B9E\u9645\u6267\u884C\u4E86\u4EC0\u4E48\u547D\u4EE4/\u64CD\u4F5C\u3001\u770B\u5230\u4E86\u4EC0\u4E48\u8F93\u51FA\uFF1F\u2461 \u6709\u6CA1\u6709\u54EA\u4E00\u6761\u4F60\u6CA1\u80FD\u5B9E\u6D4B\uFF1F\u6CA1\u80FD\u5B9E\u6D4B\u7684\uFF0C\u662F**\u88AB\u6D4B\u7269\u6709\u7F3A\u9677**\u3001\u8FD8\u662F**\u9700\u6C42\u672C\u8EAB\u8C41\u514D**\u3001\u8FD8\u662F**\u4F60\u5361\u4F4F\u4E86\u9700\u8981\u4EBA\u5E2E\u5FD9**\u2014\u2014\u9010\u6761\u8BF4\u6E05\u662F\u54EA\u4E00\u79CD\u3002\u2462 \u76F8\u90BB\u4E09\u533A/\u76F8\u90BB\u8DEF\u5F84\u6539\u52A8\u524D\u540E\u884C\u4E3A\u4E00\u81F4\u5417\uFF1F
175125
+
175126
+ \u5224\u636E\u6765\u81EA\u5DE5\u5355\u63CF\u8FF0\u672C\u8EAB\u2014\u2014**\u6CA1\u6709\u771F\u5B9E\u6267\u884C\u8FC7\u4E0D\u7B97\u9A8C\u8BC1\u8FC7**\u3002\u63CF\u8FF0\u91CC\u6CA1\u6709\u53EF\u6267\u884C\u7684\u590D\u73B0\u65B9\u5F0F\u65F6\uFF0C\u5148\u5982\u5B9E\u8BF4\u660E\u8FD9\u4E00\u70B9\uFF0C\u518D\u7ED9\u51FA\u4F60\u5B9E\u9645\u91C7\u7528\u7684\u9A8C\u8BC1\u65B9\u5F0F\uFF0C\u4E0D\u8981\u56E0\u4E3A\u300C\u4EE3\u7801\u770B\u8D77\u6765\u5BF9\u300D\u5C31\u5224\u901A\u8FC7\u3002
175127
+
175128
+ **\u300C\u76F8\u90BB\u8DEF\u5F84\u6CA1\u6253\u574F\u300D\u2260\u300C\u65E2\u6709\u6D4B\u8BD5\u5168\u7EFF\u300D**\uFF1A\u672C\u6B21\u65B0\u5F15\u5165\u6216\u6539\u5199\u7684\u5224\u65AD\uFF0C\u5728\u5B83\u7684\u6BCF\u4E00\u79CD\u72B6\u6001\u4E0B\u90FD\u8981\u6709\u5BF9\u5E94\u8BC1\u636E\u3002\u65E7\u5957\u4EF6\u91CC\u672C\u6765\u5C31\u6CA1\u6709\u8FD9\u4E9B\u72B6\u6001\u7684\u7528\u4F8B\uFF0C\u5168\u7EFF\u53EA\u8BC1\u660E\u300C\u6CA1\u6253\u574F\u65E7\u884C\u4E3A\u300D\u3002
175129
+
175130
+ \u9A8C\u4E0D\u8FC7\u5982\u5B9E\u6253\u56DE\u300C\u4FEE\u590D\u5B9E\u73B0\u300D\u5E76\u5199\u6E05\u5361\u5728\u54EA\u4E00\u6B65\u3001\u5B9E\u9645\u770B\u5230\u4EC0\u4E48\u3002`,
174932
175131
  isFinalOutput: true
174933
175132
  }
174934
175133
  ];
@@ -184706,8 +184905,10 @@ var init_postgres_control_plane = __esm({
184706
184905
  name text NOT NULL,
184707
184906
  avatar text, -- "blob:<hash>"\uFF0C\u7A7A=\u9ED8\u8BA4
184708
184907
  status text NOT NULL, -- active | suspended
184709
- created_at timestamptz NOT NULL
184908
+ created_at timestamptz NOT NULL,
184909
+ onboarding_variant text -- \u767B\u5F55\u540E\u52A9\u7406\u5F15\u5BFC\u53D8\u4F53 A|B\uFF1BNULL=\u7F3A\u7701\u89C6\u4E3A A
184710
184910
  )`);
184911
+ await pool.query(`ALTER TABLE "${s2}".companies ADD COLUMN IF NOT EXISTS onboarding_variant text`);
184711
184912
  await pool.query(`
184712
184913
  CREATE TABLE IF NOT EXISTS "${s2}".company_members (
184713
184914
  company_id text NOT NULL,
@@ -184752,8 +184953,8 @@ var init_postgres_control_plane = __esm({
184752
184953
  // —— 公司 ——
184753
184954
  async createCompany(c) {
184754
184955
  await this.pool.query(
184755
- `INSERT INTO ${this.s}.companies (id, slug, name, avatar, status, created_at) VALUES ($1,$2,$3,$4,$5,$6)`,
184756
- [c.id, c.slug, c.name, c.avatar ?? null, c.status, c.createdAt]
184956
+ `INSERT INTO ${this.s}.companies (id, slug, name, avatar, status, created_at, onboarding_variant) VALUES ($1,$2,$3,$4,$5,$6,$7)`,
184957
+ [c.id, c.slug, c.name, c.avatar ?? null, c.status, c.createdAt, c.onboardingVariant ?? null]
184757
184958
  );
184758
184959
  }
184759
184960
  async getCompany(id) {
@@ -184783,6 +184984,10 @@ var init_postgres_control_plane = __esm({
184783
184984
  args.push(patch.status);
184784
184985
  sets.push(`status = $${args.length}`);
184785
184986
  }
184987
+ if (patch.onboardingVariant !== void 0) {
184988
+ args.push(patch.onboardingVariant);
184989
+ sets.push(`onboarding_variant = $${args.length}`);
184990
+ }
184786
184991
  args.push(id);
184787
184992
  const sql = sets.length ? `UPDATE ${this.s}.companies SET ${sets.join(", ")} WHERE id = $${args.length}` : `SELECT 1 FROM ${this.s}.companies WHERE id = $${args.length}`;
184788
184993
  const r = await this.pool.query(sql, args);
@@ -185046,7 +185251,8 @@ var init_postgres_control_plane = __esm({
185046
185251
  name: row.name,
185047
185252
  ...row.avatar !== null && row.avatar !== void 0 ? { avatar: row.avatar } : {},
185048
185253
  status: row.status,
185049
- createdAt: new Date(row.created_at).toISOString()
185254
+ createdAt: new Date(row.created_at).toISOString(),
185255
+ ...row.onboarding_variant ? { onboardingVariant: row.onboarding_variant } : {}
185050
185256
  });
185051
185257
  rowToMember = (row) => ({
185052
185258
  companyId: row.company_id,
@@ -192366,7 +192572,7 @@ async function runCli(argv, println = console.log) {
192366
192572
  return uploaded;
192367
192573
  };
192368
192574
  const STAGE_COMMANDS = /* @__PURE__ */ new Set(["link", "spawn", "unlink", "cancel", "freeze", "cancel-part", "edit", "assign", "reopen"]);
192369
- const GLOBAL_NON_FIELD_FLAGS = /* @__PURE__ */ new Set(["server", "token", "dir", "set-json", "clear"]);
192575
+ const GLOBAL_NON_FIELD_FLAGS = /* @__PURE__ */ new Set(["server", "token", "dir", "set-json", "clear", "workspace"]);
192370
192576
  const SPAWN_OWN_FLAGS = /* @__PURE__ */ new Set(["type", "owner", "workspace", "persistence", "title", "brief", "description", "input", "parts-file"]);
192371
192577
  const EDIT_OWN_FLAGS = /* @__PURE__ */ new Set(["title", "brief"]);
192372
192578
  const fieldsFromFlags = (ownFlags) => {
@@ -194206,7 +194412,7 @@ function syncRuntimeAssets(candidateRoots, binDir) {
194206
194412
  }
194207
194413
 
194208
194414
  // src/index.ts
194209
- var PKG_VERSION = true ? "0.1.84" : "dev";
194415
+ var PKG_VERSION = true ? "0.1.85" : "dev";
194210
194416
  var OASIS_DIR = path29.join(os9.homedir(), ".oasis");
194211
194417
  var CONFIG_FILE = path29.join(OASIS_DIR, "node-config.json");
194212
194418
  var PID_FILE = path29.join(OASIS_DIR, "node.pid");
@@ -194279,9 +194485,11 @@ exec node "${BIN_FILE}" "$@"
194279
194485
  function setupAutostart() {
194280
194486
  const cmd = `${process.execPath} "${BIN_FILE}" --_daemon`;
194281
194487
  const home = os9.homedir();
194488
+ const pnpmHome = process.env["PNPM_HOME"] || path29.join(home, ".local", "share", "pnpm");
194282
194489
  const extraBins = [
194283
194490
  path29.join(home, ".npm-global", "bin"),
194284
194491
  path29.join(home, ".local", "bin"),
194492
+ path29.join(pnpmHome, "bin"),
194285
194493
  "/usr/local/bin"
194286
194494
  ];
194287
194495
  const daemonPath = sanitizeDaemonPath([process.env["PATH"] ?? "", ...extraBins].filter(Boolean).join(":"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test",
3
- "version": "0.1.84",
3
+ "version": "0.1.85",
4
4
  "description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
5
5
  "bin": {
6
6
  "oasis": "./dist/index.js"