@alook/cli 0.1.31 → 0.1.33

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/index.js CHANGED
@@ -15960,6 +15960,7 @@ __export(exports_schema, {
15960
15960
  user: () => user,
15961
15961
  taskMessage: () => taskMessage,
15962
15962
  session: () => session,
15963
+ nativeOauthAttempt: () => nativeOauthAttempt,
15963
15964
  messageFlag: () => messageFlag,
15964
15965
  message: () => message,
15965
15966
  member: () => member,
@@ -15986,7 +15987,11 @@ __export(exports_schema, {
15986
15987
  agentEmailAccount: () => agentEmailAccount,
15987
15988
  agentAccess: () => agentAccess,
15988
15989
  agent: () => agent,
15989
- account: () => account
15990
+ account: () => account,
15991
+ NATIVE_OAUTH_STATUSES: () => NATIVE_OAUTH_STATUSES,
15992
+ NATIVE_OAUTH_PROVIDERS: () => NATIVE_OAUTH_PROVIDERS,
15993
+ NATIVE_OAUTH_PLATFORMS: () => NATIVE_OAUTH_PLATFORMS,
15994
+ NATIVE_OAUTH_FAILURE_CODES: () => NATIVE_OAUTH_FAILURE_CODES
15990
15995
  });
15991
15996
  init_nanoid();
15992
15997
 
@@ -16051,6 +16056,7 @@ var TERMINAL_MEETING_STATUSES = [
16051
16056
  MeetingStatus.COMPLETED,
16052
16057
  MeetingStatus.FAILED
16053
16058
  ];
16059
+ var COMMUNITY_BOT_LIMIT_PER_OWNER = 20;
16054
16060
  var COMMUNITY_BOT_NAME_MIN = 1;
16055
16061
  var COMMUNITY_BOT_NAME_MAX = 32;
16056
16062
  var COMMUNITY_BOT_DESCRIPTION_MAX = 1024;
@@ -16120,6 +16126,119 @@ var verification = sqliteTable("verification", {
16120
16126
  createdAt: text("createdAt").notNull().$defaultFn(() => new Date().toISOString()),
16121
16127
  updatedAt: text("updatedAt").notNull().$defaultFn(() => new Date().toISOString())
16122
16128
  });
16129
+ var NATIVE_OAUTH_PROVIDERS = ["github", "google"];
16130
+ var NATIVE_OAUTH_PLATFORMS = [
16131
+ "macos",
16132
+ "windows",
16133
+ "linux",
16134
+ "ios",
16135
+ "android"
16136
+ ];
16137
+ var NATIVE_OAUTH_STATUSES = [
16138
+ "pending",
16139
+ "opened",
16140
+ "ready",
16141
+ "exchanging",
16142
+ "consumed",
16143
+ "failed",
16144
+ "cancelled",
16145
+ "replaced"
16146
+ ];
16147
+ var NATIVE_OAUTH_FAILURE_CODES = [
16148
+ "access_denied",
16149
+ "provider_error",
16150
+ "oauth_callback_failed",
16151
+ "start_failed",
16152
+ "invalid_handoff"
16153
+ ];
16154
+ var nativeOauthAttempt = sqliteTable("native_oauth_attempt", {
16155
+ id: text("id").primaryKey(),
16156
+ instanceKeyHash: text("instance_key_hash").notNull(),
16157
+ stateHash: text("state_hash").notNull(),
16158
+ pkceChallenge: text("pkce_challenge").notNull(),
16159
+ provider: text("provider").$type().notNull(),
16160
+ platform: text("platform").$type().notNull(),
16161
+ redirectPath: text("redirect_path").notNull(),
16162
+ status: text("status").$type().notNull().default("pending"),
16163
+ handoffCodeHash: text("handoff_code_hash"),
16164
+ handoffExpiresAt: integer2("handoff_expires_at"),
16165
+ authKind: text("auth_kind").$type(),
16166
+ failureCode: text("failure_code").$type(),
16167
+ attemptExpiresAt: integer2("attempt_expires_at").notNull(),
16168
+ createdAt: integer2("created_at").notNull(),
16169
+ updatedAt: integer2("updated_at").notNull(),
16170
+ openedAt: integer2("opened_at"),
16171
+ readyAt: integer2("ready_at"),
16172
+ consumedAt: integer2("consumed_at"),
16173
+ failedAt: integer2("failed_at"),
16174
+ cancelledAt: integer2("cancelled_at"),
16175
+ replacedAt: integer2("replaced_at")
16176
+ }, (t) => [
16177
+ index("idx_native_oauth_attempt_instance_status").on(t.instanceKeyHash, t.status),
16178
+ index("idx_native_oauth_attempt_id_status_expiry").on(t.id, t.status, t.attemptExpiresAt),
16179
+ index("idx_native_oauth_attempt_terminal_cleanup").on(t.status, t.updatedAt),
16180
+ uniqueIndex("uq_native_oauth_attempt_instance_live").on(t.instanceKeyHash).where(sql`status IN ('pending', 'opened', 'ready', 'exchanging')`),
16181
+ uniqueIndex("uq_native_oauth_attempt_handoff_hash").on(t.handoffCodeHash).where(sql`handoff_code_hash IS NOT NULL`),
16182
+ check2("ck_native_oauth_attempt_id", sql`length(${t.id}) BETWEEN 22 AND 64 AND ${t.id} NOT GLOB '*[^A-Za-z0-9_-]*'`),
16183
+ check2("ck_native_oauth_attempt_hashes", sql`length(${t.instanceKeyHash}) = 64 AND ${t.instanceKeyHash} NOT GLOB '*[^0-9a-f]*'
16184
+ AND length(${t.stateHash}) = 64 AND ${t.stateHash} NOT GLOB '*[^0-9a-f]*'
16185
+ AND length(${t.pkceChallenge}) = 43 AND ${t.pkceChallenge} NOT GLOB '*[^A-Za-z0-9_-]*'
16186
+ AND (${t.handoffCodeHash} IS NULL OR (length(${t.handoffCodeHash}) = 64 AND ${t.handoffCodeHash} NOT GLOB '*[^0-9a-f]*'))`),
16187
+ check2("ck_native_oauth_attempt_enums", sql`${t.provider} IN ('github', 'google')
16188
+ AND ${t.platform} IN ('macos', 'windows', 'linux', 'ios', 'android')
16189
+ AND ${t.status} IN ('pending', 'opened', 'ready', 'exchanging', 'consumed', 'failed', 'cancelled', 'replaced')
16190
+ AND (${t.authKind} IS NULL OR ${t.authKind} IN ('signin', 'signup'))
16191
+ AND (${t.failureCode} IS NULL OR ${t.failureCode} IN ('access_denied', 'provider_error', 'oauth_callback_failed', 'start_failed', 'invalid_handoff'))`),
16192
+ check2("ck_native_oauth_attempt_redirect", sql`length(${t.redirectPath}) BETWEEN 1 AND 2048
16193
+ AND substr(${t.redirectPath}, 1, 1) = '/'
16194
+ AND substr(${t.redirectPath}, 1, 2) <> '//'
16195
+ AND instr(${t.redirectPath}, char(92)) = 0`),
16196
+ check2("ck_native_oauth_attempt_epochs", sql`typeof(${t.createdAt}) = 'integer' AND ${t.createdAt} BETWEEN 0 AND 9007199254740991
16197
+ AND typeof(${t.updatedAt}) = 'integer' AND ${t.updatedAt} BETWEEN ${t.createdAt} AND 9007199254740991
16198
+ AND typeof(${t.attemptExpiresAt}) = 'integer' AND ${t.attemptExpiresAt} = ${t.createdAt} + 600000
16199
+ AND (${t.handoffExpiresAt} IS NULL OR (typeof(${t.handoffExpiresAt}) = 'integer' AND ${t.handoffExpiresAt} <= ${t.attemptExpiresAt}))`),
16200
+ check2("ck_native_oauth_attempt_state", sql`(
16201
+ ${t.status} = 'pending'
16202
+ AND ${t.openedAt} IS NULL AND ${t.readyAt} IS NULL AND ${t.consumedAt} IS NULL
16203
+ AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
16204
+ AND ${t.handoffCodeHash} IS NULL AND ${t.handoffExpiresAt} IS NULL
16205
+ AND ${t.authKind} IS NULL AND ${t.failureCode} IS NULL
16206
+ ) OR (
16207
+ ${t.status} = 'opened'
16208
+ AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NULL AND ${t.consumedAt} IS NULL
16209
+ AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
16210
+ AND ${t.handoffCodeHash} IS NULL AND ${t.handoffExpiresAt} IS NULL
16211
+ AND ${t.authKind} IS NULL AND ${t.failureCode} IS NULL
16212
+ ) OR (
16213
+ ${t.status} IN ('ready', 'exchanging')
16214
+ AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NOT NULL AND ${t.consumedAt} IS NULL
16215
+ AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
16216
+ AND ${t.handoffCodeHash} IS NOT NULL AND ${t.handoffExpiresAt} IS NOT NULL
16217
+ AND ${t.handoffExpiresAt} = ${t.readyAt} + 120000
16218
+ AND ${t.authKind} IS NOT NULL AND ${t.failureCode} IS NULL
16219
+ ) OR (
16220
+ ${t.status} = 'consumed'
16221
+ AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NOT NULL AND ${t.consumedAt} IS NOT NULL
16222
+ AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
16223
+ AND ${t.handoffCodeHash} IS NOT NULL AND ${t.handoffExpiresAt} IS NOT NULL
16224
+ AND ${t.authKind} IS NOT NULL AND ${t.failureCode} IS NULL
16225
+ ) OR (
16226
+ ${t.status} = 'failed'
16227
+ AND ${t.consumedAt} IS NULL AND ${t.failedAt} IS NOT NULL
16228
+ AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
16229
+ AND ${t.failureCode} IS NOT NULL
16230
+ ) OR (
16231
+ ${t.status} = 'cancelled'
16232
+ AND ${t.consumedAt} IS NULL AND ${t.cancelledAt} IS NOT NULL
16233
+ AND ${t.failedAt} IS NULL AND ${t.replacedAt} IS NULL
16234
+ AND ${t.failureCode} IS NULL
16235
+ ) OR (
16236
+ ${t.status} = 'replaced'
16237
+ AND ${t.consumedAt} IS NULL AND ${t.replacedAt} IS NOT NULL
16238
+ AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL
16239
+ AND ${t.failureCode} IS NULL
16240
+ )`)
16241
+ ]);
16123
16242
  var workspace = sqliteTable("workspace", {
16124
16243
  id: text("id").primaryKey().$defaultFn(() => "sp_" + nanoid3()),
16125
16244
  name: text("name").notNull(),
@@ -17676,6 +17795,10 @@ var CommunityBotPatchRequestSchema = exports_external.object({
17676
17795
  var CommunityBotAddToServerRequestSchema = exports_external.object({
17677
17796
  botId: exports_external.string().min(1)
17678
17797
  });
17798
+ var CommunityServerOnboardRequestSchema = exports_external.strictObject({
17799
+ botIds: exports_external.array(exports_external.string().min(1).max(128)).min(1).max(COMMUNITY_BOT_LIMIT_PER_OWNER).refine((ids) => new Set(ids).size === ids.length, "botIds must be unique"),
17800
+ wakePrompt: exports_external.string().max(32768).refine((value) => value.trim().length > 0, "wakePrompt is required")
17801
+ });
17679
17802
  var CommunityAgentMessageContentSchema = exports_external.object({ text: exports_external.string().max(MAX_MESSAGE_CONTENT_LENGTH).default("") }).catchall(exports_external.unknown());
17680
17803
  var CommunityAgentSeqSchema = exports_external.number().int().min(0);
17681
17804
  var CommunityAgentPositiveSeqSchema = exports_external.number().int().min(1);
@@ -17873,6 +17996,13 @@ var HostCommandSchema = exports_external.discriminatedUnion("type", [
17873
17996
  launchId: exports_external.string().min(1),
17874
17997
  unreadNotice: exports_external.unknown()
17875
17998
  }),
17999
+ exports_external.object({
18000
+ type: exports_external.literal("agent:event"),
18001
+ agentId: exports_external.string().min(1),
18002
+ config: exports_external.unknown(),
18003
+ launchId: exports_external.string().min(1),
18004
+ prompt: exports_external.string().min(1).max(32768)
18005
+ }),
17876
18006
  exports_external.object({
17877
18007
  type: exports_external.literal("agent:stop"),
17878
18008
  agentId: exports_external.string().min(1)
@@ -18325,6 +18455,15 @@ function createLogger(opts) {
18325
18455
 
18326
18456
  // ../shared/src/db/queries/_chunk.ts
18327
18457
  var D1_MAX_BIND_PARAMS = 100;
18458
+ function maxInParams(fixedParams) {
18459
+ if (!Number.isInteger(fixedParams) || fixedParams < 0) {
18460
+ throw new Error("fixed params must be a non-negative integer");
18461
+ }
18462
+ if (fixedParams >= D1_MAX_BIND_PARAMS) {
18463
+ throw new Error("fixed params must leave room for at least one IN parameter");
18464
+ }
18465
+ return D1_MAX_BIND_PARAMS - fixedParams;
18466
+ }
18328
18467
  function maxRowsPerInsert(paramsPerRow) {
18329
18468
  if (paramsPerRow < 1)
18330
18469
  throw new Error("paramsPerRow must be >= 1");
@@ -18416,6 +18555,7 @@ var AGENT_MESSAGE_COLUMNS = {
18416
18555
  replyToId: communityMessage.replyToId
18417
18556
  };
18418
18557
  var channelJoinBaselineGuard = sql`${communityMessage.createdAt} > COALESCE(${communityChannelMember.addedAt}, ${communityServerMember.joinedAt}, '')`;
18558
+ var AGENT_UNREAD_CHANNEL_CHUNK_SIZE = maxInParams(13);
18419
18559
 
18420
18560
  // ../shared/src/db/queries/community/mention.ts
18421
18561
  var MENTION_INSERT_MAX_ROWS = maxRowsPerInsert(5);
@@ -19028,6 +19168,10 @@ var serverRailCommandSchema = exports_external.discriminatedUnion("kind", [
19028
19168
  var serverRailCommitRequestSchema = exports_external.strictObject({
19029
19169
  commands: exports_external.array(serverRailCommandSchema).min(1).max(MAX_SERVER_RAIL_COMMANDS)
19030
19170
  });
19171
+ // ../shared/src/db/queries/native-oauth.ts
19172
+ var ATTEMPT_TTL_MS = 10 * 60 * 1000;
19173
+ var HANDOFF_TTL_MS = 2 * 60 * 1000;
19174
+ var RETENTION_MS = 24 * 60 * 60 * 1000;
19031
19175
  // ../shared/src/db/queries/task.ts
19032
19176
  var DEFAULT_STALE_SECONDS = Number(process.env.ALOOK_STALE_DISPATCH_TIMEOUT_S) || 20;
19033
19177
  var DEFAULT_STALE_RUNNING_SECONDS = Number(process.env.ALOOK_STALE_RUNNING_TIMEOUT_S) || 3600;
@@ -19059,6 +19203,80 @@ var FTS_KEYWORDS = new Set(["and", "or", "not", "near"]);
19059
19203
  var FOLDER_ITEM_INSERT_MAX_ROWS = maxRowsPerInsert(3);
19060
19204
  // ../shared/src/db/queries/community/diagnostic-report.ts
19061
19205
  var diagnosticOwner = alias(user, "diagnostic_owner");
19206
+ // ../shared/src/lib/safe-redirect.ts
19207
+ var MAX_REDIRECT_BYTES = 2048;
19208
+ var CONTROL_CHARACTERS = /[\u0000-\u001f\u007f]/;
19209
+ function isSafeCandidate(value) {
19210
+ return value.startsWith("/") && !value.startsWith("//") && !value.includes("\\") && !value.includes("#") && !CONTROL_CHARACTERS.test(value);
19211
+ }
19212
+ function isSafeRedirectPath(value) {
19213
+ if (new TextEncoder().encode(value).byteLength > MAX_REDIRECT_BYTES)
19214
+ return false;
19215
+ if (!isSafeCandidate(value))
19216
+ return false;
19217
+ let decoded = value;
19218
+ for (let depth = 0;depth < 8; depth += 1) {
19219
+ let next;
19220
+ try {
19221
+ next = decodeURIComponent(decoded);
19222
+ } catch {
19223
+ return depth > 0;
19224
+ }
19225
+ if (next === decoded)
19226
+ break;
19227
+ if (!isSafeCandidate(next))
19228
+ return false;
19229
+ decoded = next;
19230
+ if (depth === 7)
19231
+ return false;
19232
+ }
19233
+ try {
19234
+ const base = new URL("https://alook.invalid");
19235
+ const resolved = new URL(value, base);
19236
+ return resolved.origin === base.origin;
19237
+ } catch {
19238
+ return false;
19239
+ }
19240
+ }
19241
+
19242
+ // ../shared/src/lib/native-oauth-contract.ts
19243
+ var ATTEMPT_ID = /^[A-Za-z0-9_-]{22,64}$/;
19244
+ var SHA256_HEX = /^[0-9a-f]{64}$/;
19245
+ var BASE64URL_32_BYTES = /^[A-Za-z0-9_-]{43}$/;
19246
+ var HANDOFF_CODE = /^[A-Za-z0-9_-]{32,128}$/;
19247
+ var nativeOauthProviderSchema = exports_external.enum(["github", "google"]);
19248
+ var nativeOauthPlatformSchema = exports_external.enum([
19249
+ "macos",
19250
+ "windows",
19251
+ "linux",
19252
+ "ios",
19253
+ "android"
19254
+ ]);
19255
+ var nativeOauthAttemptIdSchema = exports_external.string().regex(ATTEMPT_ID);
19256
+ var nativeOauthHandoffCodeSchema = exports_external.string().regex(HANDOFF_CODE);
19257
+ var nativeOauthFailureCodeSchema = exports_external.enum([
19258
+ "access_denied",
19259
+ "provider_error",
19260
+ "oauth_callback_failed",
19261
+ "start_failed",
19262
+ "invalid_handoff"
19263
+ ]);
19264
+ var nativeOauthRegistrationSchema = exports_external.object({
19265
+ attemptId: nativeOauthAttemptIdSchema,
19266
+ stateHash: exports_external.string().regex(SHA256_HEX),
19267
+ codeChallenge: exports_external.string().regex(BASE64URL_32_BYTES),
19268
+ instanceKeyHash: exports_external.string().regex(SHA256_HEX),
19269
+ platform: nativeOauthPlatformSchema,
19270
+ provider: nativeOauthProviderSchema,
19271
+ redirectPath: exports_external.string().refine(isSafeRedirectPath)
19272
+ }).strict();
19273
+ var nativeOauthExchangeSchema = exports_external.object({
19274
+ attemptId: nativeOauthAttemptIdSchema,
19275
+ state: exports_external.string().regex(BASE64URL_32_BYTES),
19276
+ verifier: exports_external.string().regex(BASE64URL_32_BYTES),
19277
+ code: nativeOauthHandoffCodeSchema
19278
+ }).strict();
19279
+ var nativeOauthProofSchema = nativeOauthExchangeSchema.omit({ code: true }).strict();
19062
19280
  // ../shared/src/semver.ts
19063
19281
  function semverGte(a, b) {
19064
19282
  const pa = a.split(".").map(Number);
@@ -15869,6 +15869,7 @@ __export(exports_schema, {
15869
15869
  user: () => user,
15870
15870
  taskMessage: () => taskMessage,
15871
15871
  session: () => session,
15872
+ nativeOauthAttempt: () => nativeOauthAttempt,
15872
15873
  messageFlag: () => messageFlag,
15873
15874
  message: () => message,
15874
15875
  member: () => member,
@@ -15895,7 +15896,11 @@ __export(exports_schema, {
15895
15896
  agentEmailAccount: () => agentEmailAccount,
15896
15897
  agentAccess: () => agentAccess,
15897
15898
  agent: () => agent,
15898
- account: () => account
15899
+ account: () => account,
15900
+ NATIVE_OAUTH_STATUSES: () => NATIVE_OAUTH_STATUSES,
15901
+ NATIVE_OAUTH_PROVIDERS: () => NATIVE_OAUTH_PROVIDERS,
15902
+ NATIVE_OAUTH_PLATFORMS: () => NATIVE_OAUTH_PLATFORMS,
15903
+ NATIVE_OAUTH_FAILURE_CODES: () => NATIVE_OAUTH_FAILURE_CODES
15899
15904
  });
15900
15905
  init_nanoid();
15901
15906
 
@@ -15960,6 +15965,7 @@ var TERMINAL_MEETING_STATUSES = [
15960
15965
  MeetingStatus.COMPLETED,
15961
15966
  MeetingStatus.FAILED
15962
15967
  ];
15968
+ var COMMUNITY_BOT_LIMIT_PER_OWNER = 20;
15963
15969
  var COMMUNITY_BOT_NAME_MIN = 1;
15964
15970
  var COMMUNITY_BOT_NAME_MAX = 32;
15965
15971
  var COMMUNITY_BOT_DESCRIPTION_MAX = 1024;
@@ -16025,6 +16031,119 @@ var verification = sqliteTable("verification", {
16025
16031
  createdAt: text("createdAt").notNull().$defaultFn(() => new Date().toISOString()),
16026
16032
  updatedAt: text("updatedAt").notNull().$defaultFn(() => new Date().toISOString())
16027
16033
  });
16034
+ var NATIVE_OAUTH_PROVIDERS = ["github", "google"];
16035
+ var NATIVE_OAUTH_PLATFORMS = [
16036
+ "macos",
16037
+ "windows",
16038
+ "linux",
16039
+ "ios",
16040
+ "android"
16041
+ ];
16042
+ var NATIVE_OAUTH_STATUSES = [
16043
+ "pending",
16044
+ "opened",
16045
+ "ready",
16046
+ "exchanging",
16047
+ "consumed",
16048
+ "failed",
16049
+ "cancelled",
16050
+ "replaced"
16051
+ ];
16052
+ var NATIVE_OAUTH_FAILURE_CODES = [
16053
+ "access_denied",
16054
+ "provider_error",
16055
+ "oauth_callback_failed",
16056
+ "start_failed",
16057
+ "invalid_handoff"
16058
+ ];
16059
+ var nativeOauthAttempt = sqliteTable("native_oauth_attempt", {
16060
+ id: text("id").primaryKey(),
16061
+ instanceKeyHash: text("instance_key_hash").notNull(),
16062
+ stateHash: text("state_hash").notNull(),
16063
+ pkceChallenge: text("pkce_challenge").notNull(),
16064
+ provider: text("provider").$type().notNull(),
16065
+ platform: text("platform").$type().notNull(),
16066
+ redirectPath: text("redirect_path").notNull(),
16067
+ status: text("status").$type().notNull().default("pending"),
16068
+ handoffCodeHash: text("handoff_code_hash"),
16069
+ handoffExpiresAt: integer2("handoff_expires_at"),
16070
+ authKind: text("auth_kind").$type(),
16071
+ failureCode: text("failure_code").$type(),
16072
+ attemptExpiresAt: integer2("attempt_expires_at").notNull(),
16073
+ createdAt: integer2("created_at").notNull(),
16074
+ updatedAt: integer2("updated_at").notNull(),
16075
+ openedAt: integer2("opened_at"),
16076
+ readyAt: integer2("ready_at"),
16077
+ consumedAt: integer2("consumed_at"),
16078
+ failedAt: integer2("failed_at"),
16079
+ cancelledAt: integer2("cancelled_at"),
16080
+ replacedAt: integer2("replaced_at")
16081
+ }, (t) => [
16082
+ index("idx_native_oauth_attempt_instance_status").on(t.instanceKeyHash, t.status),
16083
+ index("idx_native_oauth_attempt_id_status_expiry").on(t.id, t.status, t.attemptExpiresAt),
16084
+ index("idx_native_oauth_attempt_terminal_cleanup").on(t.status, t.updatedAt),
16085
+ uniqueIndex("uq_native_oauth_attempt_instance_live").on(t.instanceKeyHash).where(sql`status IN ('pending', 'opened', 'ready', 'exchanging')`),
16086
+ uniqueIndex("uq_native_oauth_attempt_handoff_hash").on(t.handoffCodeHash).where(sql`handoff_code_hash IS NOT NULL`),
16087
+ check2("ck_native_oauth_attempt_id", sql`length(${t.id}) BETWEEN 22 AND 64 AND ${t.id} NOT GLOB '*[^A-Za-z0-9_-]*'`),
16088
+ check2("ck_native_oauth_attempt_hashes", sql`length(${t.instanceKeyHash}) = 64 AND ${t.instanceKeyHash} NOT GLOB '*[^0-9a-f]*'
16089
+ AND length(${t.stateHash}) = 64 AND ${t.stateHash} NOT GLOB '*[^0-9a-f]*'
16090
+ AND length(${t.pkceChallenge}) = 43 AND ${t.pkceChallenge} NOT GLOB '*[^A-Za-z0-9_-]*'
16091
+ AND (${t.handoffCodeHash} IS NULL OR (length(${t.handoffCodeHash}) = 64 AND ${t.handoffCodeHash} NOT GLOB '*[^0-9a-f]*'))`),
16092
+ check2("ck_native_oauth_attempt_enums", sql`${t.provider} IN ('github', 'google')
16093
+ AND ${t.platform} IN ('macos', 'windows', 'linux', 'ios', 'android')
16094
+ AND ${t.status} IN ('pending', 'opened', 'ready', 'exchanging', 'consumed', 'failed', 'cancelled', 'replaced')
16095
+ AND (${t.authKind} IS NULL OR ${t.authKind} IN ('signin', 'signup'))
16096
+ AND (${t.failureCode} IS NULL OR ${t.failureCode} IN ('access_denied', 'provider_error', 'oauth_callback_failed', 'start_failed', 'invalid_handoff'))`),
16097
+ check2("ck_native_oauth_attempt_redirect", sql`length(${t.redirectPath}) BETWEEN 1 AND 2048
16098
+ AND substr(${t.redirectPath}, 1, 1) = '/'
16099
+ AND substr(${t.redirectPath}, 1, 2) <> '//'
16100
+ AND instr(${t.redirectPath}, char(92)) = 0`),
16101
+ check2("ck_native_oauth_attempt_epochs", sql`typeof(${t.createdAt}) = 'integer' AND ${t.createdAt} BETWEEN 0 AND 9007199254740991
16102
+ AND typeof(${t.updatedAt}) = 'integer' AND ${t.updatedAt} BETWEEN ${t.createdAt} AND 9007199254740991
16103
+ AND typeof(${t.attemptExpiresAt}) = 'integer' AND ${t.attemptExpiresAt} = ${t.createdAt} + 600000
16104
+ AND (${t.handoffExpiresAt} IS NULL OR (typeof(${t.handoffExpiresAt}) = 'integer' AND ${t.handoffExpiresAt} <= ${t.attemptExpiresAt}))`),
16105
+ check2("ck_native_oauth_attempt_state", sql`(
16106
+ ${t.status} = 'pending'
16107
+ AND ${t.openedAt} IS NULL AND ${t.readyAt} IS NULL AND ${t.consumedAt} IS NULL
16108
+ AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
16109
+ AND ${t.handoffCodeHash} IS NULL AND ${t.handoffExpiresAt} IS NULL
16110
+ AND ${t.authKind} IS NULL AND ${t.failureCode} IS NULL
16111
+ ) OR (
16112
+ ${t.status} = 'opened'
16113
+ AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NULL AND ${t.consumedAt} IS NULL
16114
+ AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
16115
+ AND ${t.handoffCodeHash} IS NULL AND ${t.handoffExpiresAt} IS NULL
16116
+ AND ${t.authKind} IS NULL AND ${t.failureCode} IS NULL
16117
+ ) OR (
16118
+ ${t.status} IN ('ready', 'exchanging')
16119
+ AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NOT NULL AND ${t.consumedAt} IS NULL
16120
+ AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
16121
+ AND ${t.handoffCodeHash} IS NOT NULL AND ${t.handoffExpiresAt} IS NOT NULL
16122
+ AND ${t.handoffExpiresAt} = ${t.readyAt} + 120000
16123
+ AND ${t.authKind} IS NOT NULL AND ${t.failureCode} IS NULL
16124
+ ) OR (
16125
+ ${t.status} = 'consumed'
16126
+ AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NOT NULL AND ${t.consumedAt} IS NOT NULL
16127
+ AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
16128
+ AND ${t.handoffCodeHash} IS NOT NULL AND ${t.handoffExpiresAt} IS NOT NULL
16129
+ AND ${t.authKind} IS NOT NULL AND ${t.failureCode} IS NULL
16130
+ ) OR (
16131
+ ${t.status} = 'failed'
16132
+ AND ${t.consumedAt} IS NULL AND ${t.failedAt} IS NOT NULL
16133
+ AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
16134
+ AND ${t.failureCode} IS NOT NULL
16135
+ ) OR (
16136
+ ${t.status} = 'cancelled'
16137
+ AND ${t.consumedAt} IS NULL AND ${t.cancelledAt} IS NOT NULL
16138
+ AND ${t.failedAt} IS NULL AND ${t.replacedAt} IS NULL
16139
+ AND ${t.failureCode} IS NULL
16140
+ ) OR (
16141
+ ${t.status} = 'replaced'
16142
+ AND ${t.consumedAt} IS NULL AND ${t.replacedAt} IS NOT NULL
16143
+ AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL
16144
+ AND ${t.failureCode} IS NULL
16145
+ )`)
16146
+ ]);
16028
16147
  var workspace = sqliteTable("workspace", {
16029
16148
  id: text("id").primaryKey().$defaultFn(() => "sp_" + nanoid3()),
16030
16149
  name: text("name").notNull(),
@@ -17580,6 +17699,10 @@ var CommunityBotPatchRequestSchema = exports_external.object({
17580
17699
  var CommunityBotAddToServerRequestSchema = exports_external.object({
17581
17700
  botId: exports_external.string().min(1)
17582
17701
  });
17702
+ var CommunityServerOnboardRequestSchema = exports_external.strictObject({
17703
+ botIds: exports_external.array(exports_external.string().min(1).max(128)).min(1).max(COMMUNITY_BOT_LIMIT_PER_OWNER).refine((ids) => new Set(ids).size === ids.length, "botIds must be unique"),
17704
+ wakePrompt: exports_external.string().max(32768).refine((value) => value.trim().length > 0, "wakePrompt is required")
17705
+ });
17583
17706
  var CommunityAgentMessageContentSchema = exports_external.object({ text: exports_external.string().max(MAX_MESSAGE_CONTENT_LENGTH).default("") }).catchall(exports_external.unknown());
17584
17707
  var CommunityAgentSeqSchema = exports_external.number().int().min(0);
17585
17708
  var CommunityAgentPositiveSeqSchema = exports_external.number().int().min(1);
@@ -17777,6 +17900,13 @@ var HostCommandSchema = exports_external.discriminatedUnion("type", [
17777
17900
  launchId: exports_external.string().min(1),
17778
17901
  unreadNotice: exports_external.unknown()
17779
17902
  }),
17903
+ exports_external.object({
17904
+ type: exports_external.literal("agent:event"),
17905
+ agentId: exports_external.string().min(1),
17906
+ config: exports_external.unknown(),
17907
+ launchId: exports_external.string().min(1),
17908
+ prompt: exports_external.string().min(1).max(32768)
17909
+ }),
17780
17910
  exports_external.object({
17781
17911
  type: exports_external.literal("agent:stop"),
17782
17912
  agentId: exports_external.string().min(1)
@@ -18229,6 +18359,15 @@ function createLogger(opts) {
18229
18359
 
18230
18360
  // ../shared/src/db/queries/_chunk.ts
18231
18361
  var D1_MAX_BIND_PARAMS = 100;
18362
+ function maxInParams(fixedParams) {
18363
+ if (!Number.isInteger(fixedParams) || fixedParams < 0) {
18364
+ throw new Error("fixed params must be a non-negative integer");
18365
+ }
18366
+ if (fixedParams >= D1_MAX_BIND_PARAMS) {
18367
+ throw new Error("fixed params must leave room for at least one IN parameter");
18368
+ }
18369
+ return D1_MAX_BIND_PARAMS - fixedParams;
18370
+ }
18232
18371
  function maxRowsPerInsert(paramsPerRow) {
18233
18372
  if (paramsPerRow < 1)
18234
18373
  throw new Error("paramsPerRow must be >= 1");
@@ -18320,6 +18459,7 @@ var AGENT_MESSAGE_COLUMNS = {
18320
18459
  replyToId: communityMessage.replyToId
18321
18460
  };
18322
18461
  var channelJoinBaselineGuard = sql`${communityMessage.createdAt} > COALESCE(${communityChannelMember.addedAt}, ${communityServerMember.joinedAt}, '')`;
18462
+ var AGENT_UNREAD_CHANNEL_CHUNK_SIZE = maxInParams(13);
18323
18463
 
18324
18464
  // ../shared/src/db/queries/community/mention.ts
18325
18465
  var MENTION_INSERT_MAX_ROWS = maxRowsPerInsert(5);
@@ -18932,6 +19072,10 @@ var serverRailCommandSchema = exports_external.discriminatedUnion("kind", [
18932
19072
  var serverRailCommitRequestSchema = exports_external.strictObject({
18933
19073
  commands: exports_external.array(serverRailCommandSchema).min(1).max(MAX_SERVER_RAIL_COMMANDS)
18934
19074
  });
19075
+ // ../shared/src/db/queries/native-oauth.ts
19076
+ var ATTEMPT_TTL_MS = 10 * 60 * 1000;
19077
+ var HANDOFF_TTL_MS = 2 * 60 * 1000;
19078
+ var RETENTION_MS = 24 * 60 * 60 * 1000;
18935
19079
  // ../shared/src/db/queries/task.ts
18936
19080
  var DEFAULT_STALE_SECONDS = Number(process.env.ALOOK_STALE_DISPATCH_TIMEOUT_S) || 20;
18937
19081
  var DEFAULT_STALE_RUNNING_SECONDS = Number(process.env.ALOOK_STALE_RUNNING_TIMEOUT_S) || 3600;
@@ -18963,6 +19107,80 @@ var FTS_KEYWORDS = new Set(["and", "or", "not", "near"]);
18963
19107
  var FOLDER_ITEM_INSERT_MAX_ROWS = maxRowsPerInsert(3);
18964
19108
  // ../shared/src/db/queries/community/diagnostic-report.ts
18965
19109
  var diagnosticOwner = alias(user, "diagnostic_owner");
19110
+ // ../shared/src/lib/safe-redirect.ts
19111
+ var MAX_REDIRECT_BYTES = 2048;
19112
+ var CONTROL_CHARACTERS = /[\u0000-\u001f\u007f]/;
19113
+ function isSafeCandidate(value) {
19114
+ return value.startsWith("/") && !value.startsWith("//") && !value.includes("\\") && !value.includes("#") && !CONTROL_CHARACTERS.test(value);
19115
+ }
19116
+ function isSafeRedirectPath(value) {
19117
+ if (new TextEncoder().encode(value).byteLength > MAX_REDIRECT_BYTES)
19118
+ return false;
19119
+ if (!isSafeCandidate(value))
19120
+ return false;
19121
+ let decoded = value;
19122
+ for (let depth = 0;depth < 8; depth += 1) {
19123
+ let next;
19124
+ try {
19125
+ next = decodeURIComponent(decoded);
19126
+ } catch {
19127
+ return depth > 0;
19128
+ }
19129
+ if (next === decoded)
19130
+ break;
19131
+ if (!isSafeCandidate(next))
19132
+ return false;
19133
+ decoded = next;
19134
+ if (depth === 7)
19135
+ return false;
19136
+ }
19137
+ try {
19138
+ const base = new URL("https://alook.invalid");
19139
+ const resolved = new URL(value, base);
19140
+ return resolved.origin === base.origin;
19141
+ } catch {
19142
+ return false;
19143
+ }
19144
+ }
19145
+
19146
+ // ../shared/src/lib/native-oauth-contract.ts
19147
+ var ATTEMPT_ID = /^[A-Za-z0-9_-]{22,64}$/;
19148
+ var SHA256_HEX = /^[0-9a-f]{64}$/;
19149
+ var BASE64URL_32_BYTES = /^[A-Za-z0-9_-]{43}$/;
19150
+ var HANDOFF_CODE = /^[A-Za-z0-9_-]{32,128}$/;
19151
+ var nativeOauthProviderSchema = exports_external.enum(["github", "google"]);
19152
+ var nativeOauthPlatformSchema = exports_external.enum([
19153
+ "macos",
19154
+ "windows",
19155
+ "linux",
19156
+ "ios",
19157
+ "android"
19158
+ ]);
19159
+ var nativeOauthAttemptIdSchema = exports_external.string().regex(ATTEMPT_ID);
19160
+ var nativeOauthHandoffCodeSchema = exports_external.string().regex(HANDOFF_CODE);
19161
+ var nativeOauthFailureCodeSchema = exports_external.enum([
19162
+ "access_denied",
19163
+ "provider_error",
19164
+ "oauth_callback_failed",
19165
+ "start_failed",
19166
+ "invalid_handoff"
19167
+ ]);
19168
+ var nativeOauthRegistrationSchema = exports_external.object({
19169
+ attemptId: nativeOauthAttemptIdSchema,
19170
+ stateHash: exports_external.string().regex(SHA256_HEX),
19171
+ codeChallenge: exports_external.string().regex(BASE64URL_32_BYTES),
19172
+ instanceKeyHash: exports_external.string().regex(SHA256_HEX),
19173
+ platform: nativeOauthPlatformSchema,
19174
+ provider: nativeOauthProviderSchema,
19175
+ redirectPath: exports_external.string().refine(isSafeRedirectPath)
19176
+ }).strict();
19177
+ var nativeOauthExchangeSchema = exports_external.object({
19178
+ attemptId: nativeOauthAttemptIdSchema,
19179
+ state: exports_external.string().regex(BASE64URL_32_BYTES),
19180
+ verifier: exports_external.string().regex(BASE64URL_32_BYTES),
19181
+ code: nativeOauthHandoffCodeSchema
19182
+ }).strict();
19183
+ var nativeOauthProofSchema = nativeOauthExchangeSchema.omit({ code: true }).strict();
18966
19184
  // ../shared/src/mode.ts
18967
19185
  function isLocalUrl(url2) {
18968
19186
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alook/cli",
3
- "version": "0.1.31",
3
+ "version": "0.1.33",
4
4
  "description": "Alook CLI — Enable Your Person Colleague",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/alookai/alook#readme",