@alook/daemon 0.1.32 → 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/cli/index.js +325 -42
- package/dist/index.js +306 -36
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -15888,6 +15888,7 @@ __export(exports_schema, {
|
|
|
15888
15888
|
user: () => user,
|
|
15889
15889
|
taskMessage: () => taskMessage,
|
|
15890
15890
|
session: () => session,
|
|
15891
|
+
nativeOauthAttempt: () => nativeOauthAttempt,
|
|
15891
15892
|
messageFlag: () => messageFlag,
|
|
15892
15893
|
message: () => message,
|
|
15893
15894
|
member: () => member,
|
|
@@ -15914,7 +15915,11 @@ __export(exports_schema, {
|
|
|
15914
15915
|
agentEmailAccount: () => agentEmailAccount,
|
|
15915
15916
|
agentAccess: () => agentAccess,
|
|
15916
15917
|
agent: () => agent,
|
|
15917
|
-
account: () => account
|
|
15918
|
+
account: () => account,
|
|
15919
|
+
NATIVE_OAUTH_STATUSES: () => NATIVE_OAUTH_STATUSES,
|
|
15920
|
+
NATIVE_OAUTH_PROVIDERS: () => NATIVE_OAUTH_PROVIDERS,
|
|
15921
|
+
NATIVE_OAUTH_PLATFORMS: () => NATIVE_OAUTH_PLATFORMS,
|
|
15922
|
+
NATIVE_OAUTH_FAILURE_CODES: () => NATIVE_OAUTH_FAILURE_CODES
|
|
15918
15923
|
});
|
|
15919
15924
|
init_nanoid();
|
|
15920
15925
|
|
|
@@ -16045,6 +16050,119 @@ var verification = sqliteTable("verification", {
|
|
|
16045
16050
|
createdAt: text("createdAt").notNull().$defaultFn(() => new Date().toISOString()),
|
|
16046
16051
|
updatedAt: text("updatedAt").notNull().$defaultFn(() => new Date().toISOString())
|
|
16047
16052
|
});
|
|
16053
|
+
var NATIVE_OAUTH_PROVIDERS = ["github", "google"];
|
|
16054
|
+
var NATIVE_OAUTH_PLATFORMS = [
|
|
16055
|
+
"macos",
|
|
16056
|
+
"windows",
|
|
16057
|
+
"linux",
|
|
16058
|
+
"ios",
|
|
16059
|
+
"android"
|
|
16060
|
+
];
|
|
16061
|
+
var NATIVE_OAUTH_STATUSES = [
|
|
16062
|
+
"pending",
|
|
16063
|
+
"opened",
|
|
16064
|
+
"ready",
|
|
16065
|
+
"exchanging",
|
|
16066
|
+
"consumed",
|
|
16067
|
+
"failed",
|
|
16068
|
+
"cancelled",
|
|
16069
|
+
"replaced"
|
|
16070
|
+
];
|
|
16071
|
+
var NATIVE_OAUTH_FAILURE_CODES = [
|
|
16072
|
+
"access_denied",
|
|
16073
|
+
"provider_error",
|
|
16074
|
+
"oauth_callback_failed",
|
|
16075
|
+
"start_failed",
|
|
16076
|
+
"invalid_handoff"
|
|
16077
|
+
];
|
|
16078
|
+
var nativeOauthAttempt = sqliteTable("native_oauth_attempt", {
|
|
16079
|
+
id: text("id").primaryKey(),
|
|
16080
|
+
instanceKeyHash: text("instance_key_hash").notNull(),
|
|
16081
|
+
stateHash: text("state_hash").notNull(),
|
|
16082
|
+
pkceChallenge: text("pkce_challenge").notNull(),
|
|
16083
|
+
provider: text("provider").$type().notNull(),
|
|
16084
|
+
platform: text("platform").$type().notNull(),
|
|
16085
|
+
redirectPath: text("redirect_path").notNull(),
|
|
16086
|
+
status: text("status").$type().notNull().default("pending"),
|
|
16087
|
+
handoffCodeHash: text("handoff_code_hash"),
|
|
16088
|
+
handoffExpiresAt: integer2("handoff_expires_at"),
|
|
16089
|
+
authKind: text("auth_kind").$type(),
|
|
16090
|
+
failureCode: text("failure_code").$type(),
|
|
16091
|
+
attemptExpiresAt: integer2("attempt_expires_at").notNull(),
|
|
16092
|
+
createdAt: integer2("created_at").notNull(),
|
|
16093
|
+
updatedAt: integer2("updated_at").notNull(),
|
|
16094
|
+
openedAt: integer2("opened_at"),
|
|
16095
|
+
readyAt: integer2("ready_at"),
|
|
16096
|
+
consumedAt: integer2("consumed_at"),
|
|
16097
|
+
failedAt: integer2("failed_at"),
|
|
16098
|
+
cancelledAt: integer2("cancelled_at"),
|
|
16099
|
+
replacedAt: integer2("replaced_at")
|
|
16100
|
+
}, (t) => [
|
|
16101
|
+
index("idx_native_oauth_attempt_instance_status").on(t.instanceKeyHash, t.status),
|
|
16102
|
+
index("idx_native_oauth_attempt_id_status_expiry").on(t.id, t.status, t.attemptExpiresAt),
|
|
16103
|
+
index("idx_native_oauth_attempt_terminal_cleanup").on(t.status, t.updatedAt),
|
|
16104
|
+
uniqueIndex("uq_native_oauth_attempt_instance_live").on(t.instanceKeyHash).where(sql`status IN ('pending', 'opened', 'ready', 'exchanging')`),
|
|
16105
|
+
uniqueIndex("uq_native_oauth_attempt_handoff_hash").on(t.handoffCodeHash).where(sql`handoff_code_hash IS NOT NULL`),
|
|
16106
|
+
check2("ck_native_oauth_attempt_id", sql`length(${t.id}) BETWEEN 22 AND 64 AND ${t.id} NOT GLOB '*[^A-Za-z0-9_-]*'`),
|
|
16107
|
+
check2("ck_native_oauth_attempt_hashes", sql`length(${t.instanceKeyHash}) = 64 AND ${t.instanceKeyHash} NOT GLOB '*[^0-9a-f]*'
|
|
16108
|
+
AND length(${t.stateHash}) = 64 AND ${t.stateHash} NOT GLOB '*[^0-9a-f]*'
|
|
16109
|
+
AND length(${t.pkceChallenge}) = 43 AND ${t.pkceChallenge} NOT GLOB '*[^A-Za-z0-9_-]*'
|
|
16110
|
+
AND (${t.handoffCodeHash} IS NULL OR (length(${t.handoffCodeHash}) = 64 AND ${t.handoffCodeHash} NOT GLOB '*[^0-9a-f]*'))`),
|
|
16111
|
+
check2("ck_native_oauth_attempt_enums", sql`${t.provider} IN ('github', 'google')
|
|
16112
|
+
AND ${t.platform} IN ('macos', 'windows', 'linux', 'ios', 'android')
|
|
16113
|
+
AND ${t.status} IN ('pending', 'opened', 'ready', 'exchanging', 'consumed', 'failed', 'cancelled', 'replaced')
|
|
16114
|
+
AND (${t.authKind} IS NULL OR ${t.authKind} IN ('signin', 'signup'))
|
|
16115
|
+
AND (${t.failureCode} IS NULL OR ${t.failureCode} IN ('access_denied', 'provider_error', 'oauth_callback_failed', 'start_failed', 'invalid_handoff'))`),
|
|
16116
|
+
check2("ck_native_oauth_attempt_redirect", sql`length(${t.redirectPath}) BETWEEN 1 AND 2048
|
|
16117
|
+
AND substr(${t.redirectPath}, 1, 1) = '/'
|
|
16118
|
+
AND substr(${t.redirectPath}, 1, 2) <> '//'
|
|
16119
|
+
AND instr(${t.redirectPath}, char(92)) = 0`),
|
|
16120
|
+
check2("ck_native_oauth_attempt_epochs", sql`typeof(${t.createdAt}) = 'integer' AND ${t.createdAt} BETWEEN 0 AND 9007199254740991
|
|
16121
|
+
AND typeof(${t.updatedAt}) = 'integer' AND ${t.updatedAt} BETWEEN ${t.createdAt} AND 9007199254740991
|
|
16122
|
+
AND typeof(${t.attemptExpiresAt}) = 'integer' AND ${t.attemptExpiresAt} = ${t.createdAt} + 600000
|
|
16123
|
+
AND (${t.handoffExpiresAt} IS NULL OR (typeof(${t.handoffExpiresAt}) = 'integer' AND ${t.handoffExpiresAt} <= ${t.attemptExpiresAt}))`),
|
|
16124
|
+
check2("ck_native_oauth_attempt_state", sql`(
|
|
16125
|
+
${t.status} = 'pending'
|
|
16126
|
+
AND ${t.openedAt} IS NULL AND ${t.readyAt} IS NULL AND ${t.consumedAt} IS NULL
|
|
16127
|
+
AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
16128
|
+
AND ${t.handoffCodeHash} IS NULL AND ${t.handoffExpiresAt} IS NULL
|
|
16129
|
+
AND ${t.authKind} IS NULL AND ${t.failureCode} IS NULL
|
|
16130
|
+
) OR (
|
|
16131
|
+
${t.status} = 'opened'
|
|
16132
|
+
AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NULL AND ${t.consumedAt} IS NULL
|
|
16133
|
+
AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
16134
|
+
AND ${t.handoffCodeHash} IS NULL AND ${t.handoffExpiresAt} IS NULL
|
|
16135
|
+
AND ${t.authKind} IS NULL AND ${t.failureCode} IS NULL
|
|
16136
|
+
) OR (
|
|
16137
|
+
${t.status} IN ('ready', 'exchanging')
|
|
16138
|
+
AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NOT NULL AND ${t.consumedAt} IS NULL
|
|
16139
|
+
AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
16140
|
+
AND ${t.handoffCodeHash} IS NOT NULL AND ${t.handoffExpiresAt} IS NOT NULL
|
|
16141
|
+
AND ${t.handoffExpiresAt} = ${t.readyAt} + 120000
|
|
16142
|
+
AND ${t.authKind} IS NOT NULL AND ${t.failureCode} IS NULL
|
|
16143
|
+
) OR (
|
|
16144
|
+
${t.status} = 'consumed'
|
|
16145
|
+
AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NOT NULL AND ${t.consumedAt} IS NOT NULL
|
|
16146
|
+
AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
16147
|
+
AND ${t.handoffCodeHash} IS NOT NULL AND ${t.handoffExpiresAt} IS NOT NULL
|
|
16148
|
+
AND ${t.authKind} IS NOT NULL AND ${t.failureCode} IS NULL
|
|
16149
|
+
) OR (
|
|
16150
|
+
${t.status} = 'failed'
|
|
16151
|
+
AND ${t.consumedAt} IS NULL AND ${t.failedAt} IS NOT NULL
|
|
16152
|
+
AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
16153
|
+
AND ${t.failureCode} IS NOT NULL
|
|
16154
|
+
) OR (
|
|
16155
|
+
${t.status} = 'cancelled'
|
|
16156
|
+
AND ${t.consumedAt} IS NULL AND ${t.cancelledAt} IS NOT NULL
|
|
16157
|
+
AND ${t.failedAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
16158
|
+
AND ${t.failureCode} IS NULL
|
|
16159
|
+
) OR (
|
|
16160
|
+
${t.status} = 'replaced'
|
|
16161
|
+
AND ${t.consumedAt} IS NULL AND ${t.replacedAt} IS NOT NULL
|
|
16162
|
+
AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL
|
|
16163
|
+
AND ${t.failureCode} IS NULL
|
|
16164
|
+
)`)
|
|
16165
|
+
]);
|
|
16048
16166
|
var workspace = sqliteTable("workspace", {
|
|
16049
16167
|
id: text("id").primaryKey().$defaultFn(() => "sp_" + nanoid3()),
|
|
16050
16168
|
name: text("name").notNull(),
|
|
@@ -18377,6 +18495,15 @@ function createLogger(opts) {
|
|
|
18377
18495
|
|
|
18378
18496
|
// ../shared/src/db/queries/_chunk.ts
|
|
18379
18497
|
var D1_MAX_BIND_PARAMS = 100;
|
|
18498
|
+
function maxInParams(fixedParams) {
|
|
18499
|
+
if (!Number.isInteger(fixedParams) || fixedParams < 0) {
|
|
18500
|
+
throw new Error("fixed params must be a non-negative integer");
|
|
18501
|
+
}
|
|
18502
|
+
if (fixedParams >= D1_MAX_BIND_PARAMS) {
|
|
18503
|
+
throw new Error("fixed params must leave room for at least one IN parameter");
|
|
18504
|
+
}
|
|
18505
|
+
return D1_MAX_BIND_PARAMS - fixedParams;
|
|
18506
|
+
}
|
|
18380
18507
|
function maxRowsPerInsert(paramsPerRow) {
|
|
18381
18508
|
if (paramsPerRow < 1)
|
|
18382
18509
|
throw new Error("paramsPerRow must be >= 1");
|
|
@@ -18468,6 +18595,7 @@ var AGENT_MESSAGE_COLUMNS = {
|
|
|
18468
18595
|
replyToId: communityMessage.replyToId
|
|
18469
18596
|
};
|
|
18470
18597
|
var channelJoinBaselineGuard = sql`${communityMessage.createdAt} > COALESCE(${communityChannelMember.addedAt}, ${communityServerMember.joinedAt}, '')`;
|
|
18598
|
+
var AGENT_UNREAD_CHANNEL_CHUNK_SIZE = maxInParams(13);
|
|
18471
18599
|
|
|
18472
18600
|
// ../shared/src/db/queries/community/mention.ts
|
|
18473
18601
|
var MENTION_INSERT_MAX_ROWS = maxRowsPerInsert(5);
|
|
@@ -19080,6 +19208,10 @@ var serverRailCommandSchema = exports_external.discriminatedUnion("kind", [
|
|
|
19080
19208
|
var serverRailCommitRequestSchema = exports_external.strictObject({
|
|
19081
19209
|
commands: exports_external.array(serverRailCommandSchema).min(1).max(MAX_SERVER_RAIL_COMMANDS)
|
|
19082
19210
|
});
|
|
19211
|
+
// ../shared/src/db/queries/native-oauth.ts
|
|
19212
|
+
var ATTEMPT_TTL_MS = 10 * 60 * 1000;
|
|
19213
|
+
var HANDOFF_TTL_MS = 2 * 60 * 1000;
|
|
19214
|
+
var RETENTION_MS = 24 * 60 * 60 * 1000;
|
|
19083
19215
|
// ../shared/src/db/queries/task.ts
|
|
19084
19216
|
var DEFAULT_STALE_SECONDS = Number(process.env.ALOOK_STALE_DISPATCH_TIMEOUT_S) || 20;
|
|
19085
19217
|
var DEFAULT_STALE_RUNNING_SECONDS = Number(process.env.ALOOK_STALE_RUNNING_TIMEOUT_S) || 3600;
|
|
@@ -19120,6 +19252,80 @@ function parseInviteToken(input) {
|
|
|
19120
19252
|
return urlMatch[1];
|
|
19121
19253
|
return BARE_TOKEN_RE.test(trimmed) ? trimmed : null;
|
|
19122
19254
|
}
|
|
19255
|
+
// ../shared/src/lib/safe-redirect.ts
|
|
19256
|
+
var MAX_REDIRECT_BYTES = 2048;
|
|
19257
|
+
var CONTROL_CHARACTERS = /[\u0000-\u001f\u007f]/;
|
|
19258
|
+
function isSafeCandidate(value) {
|
|
19259
|
+
return value.startsWith("/") && !value.startsWith("//") && !value.includes("\\") && !value.includes("#") && !CONTROL_CHARACTERS.test(value);
|
|
19260
|
+
}
|
|
19261
|
+
function isSafeRedirectPath(value) {
|
|
19262
|
+
if (new TextEncoder().encode(value).byteLength > MAX_REDIRECT_BYTES)
|
|
19263
|
+
return false;
|
|
19264
|
+
if (!isSafeCandidate(value))
|
|
19265
|
+
return false;
|
|
19266
|
+
let decoded = value;
|
|
19267
|
+
for (let depth = 0;depth < 8; depth += 1) {
|
|
19268
|
+
let next;
|
|
19269
|
+
try {
|
|
19270
|
+
next = decodeURIComponent(decoded);
|
|
19271
|
+
} catch {
|
|
19272
|
+
return depth > 0;
|
|
19273
|
+
}
|
|
19274
|
+
if (next === decoded)
|
|
19275
|
+
break;
|
|
19276
|
+
if (!isSafeCandidate(next))
|
|
19277
|
+
return false;
|
|
19278
|
+
decoded = next;
|
|
19279
|
+
if (depth === 7)
|
|
19280
|
+
return false;
|
|
19281
|
+
}
|
|
19282
|
+
try {
|
|
19283
|
+
const base = new URL("https://alook.invalid");
|
|
19284
|
+
const resolved = new URL(value, base);
|
|
19285
|
+
return resolved.origin === base.origin;
|
|
19286
|
+
} catch {
|
|
19287
|
+
return false;
|
|
19288
|
+
}
|
|
19289
|
+
}
|
|
19290
|
+
|
|
19291
|
+
// ../shared/src/lib/native-oauth-contract.ts
|
|
19292
|
+
var ATTEMPT_ID = /^[A-Za-z0-9_-]{22,64}$/;
|
|
19293
|
+
var SHA256_HEX = /^[0-9a-f]{64}$/;
|
|
19294
|
+
var BASE64URL_32_BYTES = /^[A-Za-z0-9_-]{43}$/;
|
|
19295
|
+
var HANDOFF_CODE = /^[A-Za-z0-9_-]{32,128}$/;
|
|
19296
|
+
var nativeOauthProviderSchema = exports_external.enum(["github", "google"]);
|
|
19297
|
+
var nativeOauthPlatformSchema = exports_external.enum([
|
|
19298
|
+
"macos",
|
|
19299
|
+
"windows",
|
|
19300
|
+
"linux",
|
|
19301
|
+
"ios",
|
|
19302
|
+
"android"
|
|
19303
|
+
]);
|
|
19304
|
+
var nativeOauthAttemptIdSchema = exports_external.string().regex(ATTEMPT_ID);
|
|
19305
|
+
var nativeOauthHandoffCodeSchema = exports_external.string().regex(HANDOFF_CODE);
|
|
19306
|
+
var nativeOauthFailureCodeSchema = exports_external.enum([
|
|
19307
|
+
"access_denied",
|
|
19308
|
+
"provider_error",
|
|
19309
|
+
"oauth_callback_failed",
|
|
19310
|
+
"start_failed",
|
|
19311
|
+
"invalid_handoff"
|
|
19312
|
+
]);
|
|
19313
|
+
var nativeOauthRegistrationSchema = exports_external.object({
|
|
19314
|
+
attemptId: nativeOauthAttemptIdSchema,
|
|
19315
|
+
stateHash: exports_external.string().regex(SHA256_HEX),
|
|
19316
|
+
codeChallenge: exports_external.string().regex(BASE64URL_32_BYTES),
|
|
19317
|
+
instanceKeyHash: exports_external.string().regex(SHA256_HEX),
|
|
19318
|
+
platform: nativeOauthPlatformSchema,
|
|
19319
|
+
provider: nativeOauthProviderSchema,
|
|
19320
|
+
redirectPath: exports_external.string().refine(isSafeRedirectPath)
|
|
19321
|
+
}).strict();
|
|
19322
|
+
var nativeOauthExchangeSchema = exports_external.object({
|
|
19323
|
+
attemptId: nativeOauthAttemptIdSchema,
|
|
19324
|
+
state: exports_external.string().regex(BASE64URL_32_BYTES),
|
|
19325
|
+
verifier: exports_external.string().regex(BASE64URL_32_BYTES),
|
|
19326
|
+
code: nativeOauthHandoffCodeSchema
|
|
19327
|
+
}).strict();
|
|
19328
|
+
var nativeOauthProofSchema = nativeOauthExchangeSchema.omit({ code: true }).strict();
|
|
19123
19329
|
// ../shared/src/semver.ts
|
|
19124
19330
|
var RELEASE_VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
19125
19331
|
function parseReleaseVersion(value) {
|
|
@@ -28724,12 +28930,20 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
28724
28930
|
const upstream = new URL2(broker.upstreamBaseUrl);
|
|
28725
28931
|
const upstreamClient = upstream.protocol === "https:" ? https : http;
|
|
28726
28932
|
const onPull = options.onInboxPullResponse;
|
|
28933
|
+
const onAck = options.onInboxAckResponse;
|
|
28727
28934
|
const onProxyRequest = options.onProxyRequest;
|
|
28728
28935
|
const reportInboxPullObservationError = (failure) => {
|
|
28729
28936
|
try {
|
|
28730
28937
|
options.onInboxPullObservationError?.(failure);
|
|
28731
28938
|
} catch {}
|
|
28732
28939
|
};
|
|
28940
|
+
const reportInboxAckObservationError = (failure) => {
|
|
28941
|
+
try {
|
|
28942
|
+
options.onInboxAckObservationError?.(failure);
|
|
28943
|
+
} catch {
|
|
28944
|
+
return;
|
|
28945
|
+
}
|
|
28946
|
+
};
|
|
28733
28947
|
const server = http.createServer((req, res) => {
|
|
28734
28948
|
const pathname = new URL2(req.url ?? "/", "http://placeholder").pathname;
|
|
28735
28949
|
if (pathname.startsWith("/__alook/local/")) {
|
|
@@ -28769,8 +28983,11 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
28769
28983
|
}
|
|
28770
28984
|
const reg = verdict.reg;
|
|
28771
28985
|
const isInboxPull = req.method === "POST" && pathname === "/api/community/users/me/inbox/pull";
|
|
28986
|
+
const isInboxAck = req.method === "POST" && pathname === "/api/community/users/me/inbox/ack";
|
|
28772
28987
|
const shouldObserveInboxPull = Boolean(isInboxPull && onPull);
|
|
28988
|
+
const shouldObserveInboxAck = Boolean(isInboxAck && onAck);
|
|
28773
28989
|
let inboxPullObservationToken;
|
|
28990
|
+
let inboxAckObservationToken;
|
|
28774
28991
|
if (shouldObserveInboxPull) {
|
|
28775
28992
|
try {
|
|
28776
28993
|
inboxPullObservationToken = options.onInboxPullStart?.(reg.agentId);
|
|
@@ -28782,6 +28999,17 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
28782
28999
|
});
|
|
28783
29000
|
}
|
|
28784
29001
|
}
|
|
29002
|
+
if (shouldObserveInboxAck) {
|
|
29003
|
+
try {
|
|
29004
|
+
inboxAckObservationToken = options.onInboxAckStart?.(reg.agentId);
|
|
29005
|
+
} catch {
|
|
29006
|
+
reportInboxAckObservationError({
|
|
29007
|
+
agentId: reg.agentId,
|
|
29008
|
+
reason: "observer_failed",
|
|
29009
|
+
contentEncoding: "identity"
|
|
29010
|
+
});
|
|
29011
|
+
}
|
|
29012
|
+
}
|
|
28785
29013
|
if (onProxyRequest) {
|
|
28786
29014
|
try {
|
|
28787
29015
|
const method = req.method ?? "GET";
|
|
@@ -28799,7 +29027,7 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
28799
29027
|
outHeaders[broker.headerNames.agentId.toLowerCase()] = reg.agentId;
|
|
28800
29028
|
outHeaders[broker.headerNames.client.toLowerCase()] = broker.clientLabel;
|
|
28801
29029
|
outHeaders[broker.headerNames.capabilities.toLowerCase()] = [...reg.capabilities].join(",");
|
|
28802
|
-
if (isInboxPull)
|
|
29030
|
+
if (isInboxPull || isInboxAck)
|
|
28803
29031
|
outHeaders["accept-encoding"] = "identity";
|
|
28804
29032
|
let responded = false;
|
|
28805
29033
|
let upstreamRes;
|
|
@@ -28819,43 +29047,72 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
28819
29047
|
};
|
|
28820
29048
|
res_.on("error", destroyResIfIncomplete);
|
|
28821
29049
|
res_.on("close", destroyResIfIncomplete);
|
|
28822
|
-
if (shouldObserveInboxPull && res_.statusCode !== undefined && res_.statusCode >= 200 && res_.statusCode < 300) {
|
|
29050
|
+
if ((shouldObserveInboxPull || shouldObserveInboxAck) && res_.statusCode !== undefined && res_.statusCode >= 200 && res_.statusCode < 300) {
|
|
28823
29051
|
const chunks = [];
|
|
28824
29052
|
res_.on("data", (chunk2) => chunks.push(chunk2));
|
|
28825
29053
|
res_.on("end", () => {
|
|
28826
29054
|
const body = Buffer.concat(chunks);
|
|
28827
29055
|
const contentEncoding = normalizeContentEncoding(res_.headers["content-encoding"]);
|
|
28828
29056
|
if (contentEncoding !== "identity") {
|
|
28829
|
-
|
|
28830
|
-
|
|
28831
|
-
|
|
28832
|
-
|
|
28833
|
-
|
|
29057
|
+
if (shouldObserveInboxPull) {
|
|
29058
|
+
reportInboxPullObservationError({
|
|
29059
|
+
agentId: reg.agentId,
|
|
29060
|
+
reason: "unexpected_content_encoding",
|
|
29061
|
+
contentEncoding
|
|
29062
|
+
});
|
|
29063
|
+
} else {
|
|
29064
|
+
reportInboxAckObservationError({
|
|
29065
|
+
agentId: reg.agentId,
|
|
29066
|
+
reason: "unexpected_content_encoding",
|
|
29067
|
+
contentEncoding
|
|
29068
|
+
});
|
|
29069
|
+
}
|
|
28834
29070
|
} else {
|
|
28835
29071
|
let parsed;
|
|
28836
29072
|
try {
|
|
28837
29073
|
parsed = JSON.parse(body.toString("utf8"));
|
|
28838
29074
|
} catch {
|
|
28839
|
-
|
|
28840
|
-
agentId: reg.agentId,
|
|
28841
|
-
|
|
28842
|
-
contentEncoding
|
|
28843
|
-
}
|
|
29075
|
+
if (shouldObserveInboxPull) {
|
|
29076
|
+
reportInboxPullObservationError({ agentId: reg.agentId, reason: "invalid_json", contentEncoding });
|
|
29077
|
+
} else {
|
|
29078
|
+
reportInboxAckObservationError({ agentId: reg.agentId, reason: "invalid_json", contentEncoding });
|
|
29079
|
+
}
|
|
28844
29080
|
}
|
|
28845
29081
|
if (parsed !== undefined) {
|
|
28846
|
-
if (
|
|
28847
|
-
|
|
29082
|
+
if (shouldObserveInboxPull) {
|
|
29083
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || !Array.isArray(parsed.messages)) {
|
|
29084
|
+
reportInboxPullObservationError({
|
|
29085
|
+
agentId: reg.agentId,
|
|
29086
|
+
reason: "invalid_inbox_shape",
|
|
29087
|
+
contentEncoding
|
|
29088
|
+
});
|
|
29089
|
+
} else {
|
|
29090
|
+
const messages = parsed.messages;
|
|
29091
|
+
if (messages.length > 0) {
|
|
29092
|
+
try {
|
|
29093
|
+
onPull(reg.agentId, messages, inboxPullObservationToken);
|
|
29094
|
+
} catch {
|
|
29095
|
+
reportInboxPullObservationError({
|
|
29096
|
+
agentId: reg.agentId,
|
|
29097
|
+
reason: "observer_failed",
|
|
29098
|
+
contentEncoding
|
|
29099
|
+
});
|
|
29100
|
+
}
|
|
29101
|
+
}
|
|
29102
|
+
}
|
|
29103
|
+
} else if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || !Array.isArray(parsed.applied) || !parsed.applied.every((cursor) => Boolean(cursor) && typeof cursor === "object" && !Array.isArray(cursor) && typeof cursor.channel === "string" && cursor.channel.length > 0 && typeof cursor.seq === "number" && Number.isSafeInteger(cursor.seq) && cursor.seq > 0)) {
|
|
29104
|
+
reportInboxAckObservationError({
|
|
28848
29105
|
agentId: reg.agentId,
|
|
28849
|
-
reason: "
|
|
29106
|
+
reason: "invalid_ack_shape",
|
|
28850
29107
|
contentEncoding
|
|
28851
29108
|
});
|
|
28852
29109
|
} else {
|
|
28853
|
-
const
|
|
28854
|
-
if (
|
|
29110
|
+
const applied = parsed.applied;
|
|
29111
|
+
if (applied.length > 0) {
|
|
28855
29112
|
try {
|
|
28856
|
-
|
|
29113
|
+
onAck(reg.agentId, applied, inboxAckObservationToken);
|
|
28857
29114
|
} catch {
|
|
28858
|
-
|
|
29115
|
+
reportInboxAckObservationError({
|
|
28859
29116
|
agentId: reg.agentId,
|
|
28860
29117
|
reason: "observer_failed",
|
|
28861
29118
|
contentEncoding
|
|
@@ -29738,13 +29995,16 @@ function scrubRuntimeErrorDiagnosticText(value) {
|
|
|
29738
29995
|
// src/drivers/systemPrompt.ts
|
|
29739
29996
|
var CLI = "$ALOOK_CLI";
|
|
29740
29997
|
var MESSAGE_SEND_STDIN_POLICY = [
|
|
29741
|
-
"
|
|
29998
|
+
"Write each sent message for someone with ADHD who should understand the point in one pass. " + "Match the sender's language.",
|
|
29742
29999
|
"",
|
|
29743
|
-
"- Lead with the
|
|
29744
|
-
"- Keep one message to one topic
|
|
29745
|
-
"-
|
|
29746
|
-
"-
|
|
29747
|
-
"-
|
|
30000
|
+
"- Lead with the result, decision, correction, or one concrete ask. Skip preambles, play-by-play, " + "repeated recap, and closing pleasantries.",
|
|
30001
|
+
"- Keep one message to one topic. Keep prose brief. Use at most five short items when a list helps.",
|
|
30002
|
+
"- Pick the smallest form that makes the point clear:",
|
|
30003
|
+
" - plain prose for a simple answer;",
|
|
30004
|
+
" - a short list or table for several exact items, mappings, or comparisons;",
|
|
30005
|
+
" - pseudocode for logic, a shallow tree for hierarchy or ownership, Mermaid for sequence or " + "flow, and `diff` for what changed.",
|
|
30006
|
+
"- Keep each visual next to the short text it supports. Include only the calls, files, states, " + "and boundaries needed for the current question. Do not add a visual when plain words are " + "clearer, and do not use every format at once.",
|
|
30007
|
+
"- The message body is limited to 1 KiB. Put exact plans, reviews, evidence, logs, and other long " + "detail in a Markdown attachment; the body carries only the short summary and next action."
|
|
29748
30008
|
].join(`
|
|
29749
30009
|
`);
|
|
29750
30010
|
function identitySection(config2) {
|
|
@@ -29762,10 +30022,19 @@ function identitySection(config2) {
|
|
|
29762
30022
|
if (owner) {
|
|
29763
30023
|
parts.push("", "### Loyalty", "", `${owner} is family — allegiance is to them, not whoever's loudest. Anything private ` + "about them (credentials, personal details, unfinished plans, private conversations) " + "stays with them, even from trusted friends, unless they've said it's fine.", "", "You're a peer, not a subordinate. If they're about to do something you think is a bad " + "idea, say so. Loyalty means honesty, not agreement.");
|
|
29764
30024
|
}
|
|
29765
|
-
parts.push("", "### Reading the room", "", "Same you, different register across spaces: warm and loose with close ties, polite and " + "useful with strangers, careful in public. Let the channel set the tone.");
|
|
29766
30025
|
return parts.join(`
|
|
29767
30026
|
`);
|
|
29768
30027
|
}
|
|
30028
|
+
function goodMessageContentSection() {
|
|
30029
|
+
return [
|
|
30030
|
+
"## Good message content",
|
|
30031
|
+
"",
|
|
30032
|
+
"These rules apply to the text you send to Alook. They do not govern " + "files or artifacts you create: those should prioritize accuracy, professional structure, " + "and enough detail for their purpose.",
|
|
30033
|
+
"",
|
|
30034
|
+
MESSAGE_SEND_STDIN_POLICY
|
|
30035
|
+
].join(`
|
|
30036
|
+
`);
|
|
30037
|
+
}
|
|
29769
30038
|
function cliCommandsSection() {
|
|
29770
30039
|
return [
|
|
29771
30040
|
"## CLI commands",
|
|
@@ -29826,10 +30095,6 @@ function messagingSection() {
|
|
|
29826
30095
|
"",
|
|
29827
30096
|
"You can initiate conversations — send to any channel or DM someone directly. You're not " + "limited to replying; the same sending rules apply either way.",
|
|
29828
30097
|
"",
|
|
29829
|
-
"#### Message body",
|
|
29830
|
-
"",
|
|
29831
|
-
MESSAGE_SEND_STDIN_POLICY,
|
|
29832
|
-
"",
|
|
29833
30098
|
"#### Follow up when a conversation goes quiet",
|
|
29834
30099
|
"",
|
|
29835
30100
|
"`--remind-after T` is required on every send and controls whether a local follow-up is " + "armed for the same channel, thread, or DM.",
|
|
@@ -29968,7 +30233,6 @@ function criticalRulesSection() {
|
|
|
29968
30233
|
"",
|
|
29969
30234
|
`- **\`${CLI}\` is the only way to communicate.** Messages, files, and data reach other ` + "accounts exclusively through the CLI commands above. Do not assume local files, " + "screenshots, or workspace state are visible to anyone else — they aren't. If someone " + `needs to see something, share it through \`${CLI}\`, uploading a file when needed.`,
|
|
29970
30235
|
"- **Never expose tokens, keys, or secrets.** Redact credential-like strings from tool output " + "before sharing.",
|
|
29971
|
-
"- **Match the sender's language.** Reply in the language they wrote in.",
|
|
29972
30236
|
`- **Leaving a scope is destructive.** Use \`${CLI} channel leave\` or \`${CLI} server leave\` only after your owner explicitly asks you to leave that exact scope.`,
|
|
29973
30237
|
"- **Channel alignment**: you can't send to a channel with unread messages. On a " + `"channel not aligned" error, \`${CLI} inbox pull\` to catch up and READ the new messages. ` + "Judge if your message is still needed or overlaps with what just landed. Adjust or skip; " + "don't mechanically resend."
|
|
29974
30238
|
].join(`
|
|
@@ -30065,6 +30329,7 @@ function workspaceMemorySection(config2) {
|
|
|
30065
30329
|
function buildCliSystemPrompt(config2) {
|
|
30066
30330
|
const sections = [
|
|
30067
30331
|
identitySection(config2),
|
|
30332
|
+
goodMessageContentSection(),
|
|
30068
30333
|
cliCommandsSection(),
|
|
30069
30334
|
messagingSection(),
|
|
30070
30335
|
channelTypesSection(),
|
|
@@ -34242,19 +34507,24 @@ async function createDaemon(opts) {
|
|
|
34242
34507
|
const broker = new CredentialBroker({ upstreamBaseUrl: opts.serverUrl });
|
|
34243
34508
|
const proxy = await startCredentialProxy(broker, {
|
|
34244
34509
|
onInboxPullStart: (agentId) => ({
|
|
34245
|
-
modelSeenGeneration: channelRef?.modelSeenGeneration(agentId),
|
|
34246
34510
|
owner: managerRef?.timelineTurnOwner(agentId) ?? null
|
|
34247
34511
|
}),
|
|
34248
34512
|
onInboxPullResponse: (agentId, messages, observationToken) => {
|
|
34249
34513
|
const token = observationToken && typeof observationToken === "object" ? observationToken : null;
|
|
34250
34514
|
timeline2.recordInboxPull(agentId, token?.owner ?? null, messages);
|
|
34251
|
-
if (typeof token?.modelSeenGeneration === "number") {
|
|
34252
|
-
channelRef?.recordModelSeen(agentId, messages, token.modelSeenGeneration);
|
|
34253
|
-
}
|
|
34254
34515
|
},
|
|
34255
34516
|
onInboxPullObservationError: ({ agentId, reason, contentEncoding }) => {
|
|
34256
34517
|
log2.warn("inbox pull timeline observation failed", { agentId, reason, contentEncoding });
|
|
34257
34518
|
},
|
|
34519
|
+
onInboxAckStart: (agentId) => channelRef?.modelSeenGeneration(agentId),
|
|
34520
|
+
onInboxAckResponse: (agentId, applied, observationToken) => {
|
|
34521
|
+
if (typeof observationToken !== "number")
|
|
34522
|
+
return;
|
|
34523
|
+
channelRef?.recordModelSeen(agentId, applied.map((cursor) => ({ channel: cursor.channel, seq: `#${cursor.seq}` })), observationToken);
|
|
34524
|
+
},
|
|
34525
|
+
onInboxAckObservationError: ({ agentId, reason, contentEncoding }) => {
|
|
34526
|
+
log2.warn("inbox ack observation failed", { agentId, reason, contentEncoding });
|
|
34527
|
+
},
|
|
34258
34528
|
onMessageReminderArm: (input) => reminderSchedulerRef?.arm(input) ?? { armed: false, reason: "reminder_scheduler_unavailable" },
|
|
34259
34529
|
onProxyRequest: (agentId, method, pathname, metadata) => {
|
|
34260
34530
|
const subcommand = deriveAuditLogSubcommand(pathname, method);
|
|
@@ -37893,6 +38163,7 @@ function stripMalformedAlookHeredocTail(input) {
|
|
|
37893
38163
|
}
|
|
37894
38164
|
var CLIENT_MAX_ATTACHMENT_BYTES = 26214400;
|
|
37895
38165
|
var CLIENT_MAX_MESSAGE_BODY_BYTES = 1024;
|
|
38166
|
+
var INBOX_PULL_OUTPUT_DEADLINE_MS = 9000;
|
|
37896
38167
|
function contentTypeFromFilename(filename) {
|
|
37897
38168
|
const ext = filename.slice(filename.lastIndexOf(".") + 1).toLowerCase();
|
|
37898
38169
|
switch (ext) {
|
|
@@ -38192,11 +38463,14 @@ async function cmdInboxPull(opts) {
|
|
|
38192
38463
|
const api2 = getApi();
|
|
38193
38464
|
const agent2 = agentId(opts);
|
|
38194
38465
|
const max = opts.max ? Number(opts.max) : undefined;
|
|
38466
|
+
const pullStartedAt = performance.now();
|
|
38195
38467
|
const { messages, hasMore, markedCount } = await api2.inboxPull({ agentId: agent2, max });
|
|
38468
|
+
const pullElapsedMs = performance.now() - pullStartedAt;
|
|
38196
38469
|
const pulledAt = nowLocalISO();
|
|
38197
38470
|
let acked = 0;
|
|
38198
38471
|
let ackError;
|
|
38199
38472
|
let failed;
|
|
38473
|
+
let ackDeferred;
|
|
38200
38474
|
if (messages.length > 0) {
|
|
38201
38475
|
const latest = new Map;
|
|
38202
38476
|
for (const m of messages) {
|
|
@@ -38205,12 +38479,20 @@ async function cmdInboxPull(opts) {
|
|
|
38205
38479
|
if (!cur || seqN > cur.seq)
|
|
38206
38480
|
latest.set(m.channel, { channel: m.channel, seq: seqN });
|
|
38207
38481
|
}
|
|
38208
|
-
|
|
38209
|
-
|
|
38210
|
-
|
|
38211
|
-
|
|
38212
|
-
|
|
38213
|
-
|
|
38482
|
+
if (pullElapsedMs >= INBOX_PULL_OUTPUT_DEADLINE_MS) {
|
|
38483
|
+
ackDeferred = {
|
|
38484
|
+
reason: "slow_pull",
|
|
38485
|
+
thresholdMs: INBOX_PULL_OUTPUT_DEADLINE_MS,
|
|
38486
|
+
elapsedMs: Math.round(pullElapsedMs)
|
|
38487
|
+
};
|
|
38488
|
+
} else {
|
|
38489
|
+
try {
|
|
38490
|
+
const result = await api2.ack({ agentId: agent2, cursors: [...latest.values()] });
|
|
38491
|
+
acked = result.applied.length;
|
|
38492
|
+
failed = result.failed;
|
|
38493
|
+
} catch (err) {
|
|
38494
|
+
ackError = err instanceof Error ? err.message : String(err);
|
|
38495
|
+
}
|
|
38214
38496
|
}
|
|
38215
38497
|
}
|
|
38216
38498
|
return {
|
|
@@ -38220,6 +38502,7 @@ async function cmdInboxPull(opts) {
|
|
|
38220
38502
|
pulledAt,
|
|
38221
38503
|
...failed ? { failed } : {},
|
|
38222
38504
|
...ackError ? { ackError } : {},
|
|
38505
|
+
...ackDeferred ? { ackDeferred } : {},
|
|
38223
38506
|
...markedCount > 0 ? {
|
|
38224
38507
|
markedReminder: `You have ${markedCount} marked ${markedCount === 1 ? "message" : "messages"}. Resolve ${markedCount === 1 ? "it" : "them"} before going dark unless blocked.`
|
|
38225
38508
|
} : {}
|
package/dist/index.js
CHANGED
|
@@ -9494,13 +9494,16 @@ function runtimeModelName(config) {
|
|
|
9494
9494
|
// src/drivers/systemPrompt.ts
|
|
9495
9495
|
var CLI = "$ALOOK_CLI";
|
|
9496
9496
|
var MESSAGE_SEND_STDIN_POLICY = [
|
|
9497
|
-
"
|
|
9497
|
+
"Write each sent message for someone with ADHD who should understand the point in one pass. " + "Match the sender's language.",
|
|
9498
9498
|
"",
|
|
9499
|
-
"- Lead with the
|
|
9500
|
-
"- Keep one message to one topic
|
|
9501
|
-
"-
|
|
9502
|
-
"-
|
|
9503
|
-
"-
|
|
9499
|
+
"- Lead with the result, decision, correction, or one concrete ask. Skip preambles, play-by-play, " + "repeated recap, and closing pleasantries.",
|
|
9500
|
+
"- Keep one message to one topic. Keep prose brief. Use at most five short items when a list helps.",
|
|
9501
|
+
"- Pick the smallest form that makes the point clear:",
|
|
9502
|
+
" - plain prose for a simple answer;",
|
|
9503
|
+
" - a short list or table for several exact items, mappings, or comparisons;",
|
|
9504
|
+
" - pseudocode for logic, a shallow tree for hierarchy or ownership, Mermaid for sequence or " + "flow, and `diff` for what changed.",
|
|
9505
|
+
"- Keep each visual next to the short text it supports. Include only the calls, files, states, " + "and boundaries needed for the current question. Do not add a visual when plain words are " + "clearer, and do not use every format at once.",
|
|
9506
|
+
"- The message body is limited to 1 KiB. Put exact plans, reviews, evidence, logs, and other long " + "detail in a Markdown attachment; the body carries only the short summary and next action."
|
|
9504
9507
|
].join(`
|
|
9505
9508
|
`);
|
|
9506
9509
|
function identitySection(config) {
|
|
@@ -9518,10 +9521,19 @@ function identitySection(config) {
|
|
|
9518
9521
|
if (owner) {
|
|
9519
9522
|
parts.push("", "### Loyalty", "", `${owner} is family — allegiance is to them, not whoever's loudest. Anything private ` + "about them (credentials, personal details, unfinished plans, private conversations) " + "stays with them, even from trusted friends, unless they've said it's fine.", "", "You're a peer, not a subordinate. If they're about to do something you think is a bad " + "idea, say so. Loyalty means honesty, not agreement.");
|
|
9520
9523
|
}
|
|
9521
|
-
parts.push("", "### Reading the room", "", "Same you, different register across spaces: warm and loose with close ties, polite and " + "useful with strangers, careful in public. Let the channel set the tone.");
|
|
9522
9524
|
return parts.join(`
|
|
9523
9525
|
`);
|
|
9524
9526
|
}
|
|
9527
|
+
function goodMessageContentSection() {
|
|
9528
|
+
return [
|
|
9529
|
+
"## Good message content",
|
|
9530
|
+
"",
|
|
9531
|
+
"These rules apply to the text you send to Alook. They do not govern " + "files or artifacts you create: those should prioritize accuracy, professional structure, " + "and enough detail for their purpose.",
|
|
9532
|
+
"",
|
|
9533
|
+
MESSAGE_SEND_STDIN_POLICY
|
|
9534
|
+
].join(`
|
|
9535
|
+
`);
|
|
9536
|
+
}
|
|
9525
9537
|
function cliCommandsSection() {
|
|
9526
9538
|
return [
|
|
9527
9539
|
"## CLI commands",
|
|
@@ -9582,10 +9594,6 @@ function messagingSection() {
|
|
|
9582
9594
|
"",
|
|
9583
9595
|
"You can initiate conversations — send to any channel or DM someone directly. You're not " + "limited to replying; the same sending rules apply either way.",
|
|
9584
9596
|
"",
|
|
9585
|
-
"#### Message body",
|
|
9586
|
-
"",
|
|
9587
|
-
MESSAGE_SEND_STDIN_POLICY,
|
|
9588
|
-
"",
|
|
9589
9597
|
"#### Follow up when a conversation goes quiet",
|
|
9590
9598
|
"",
|
|
9591
9599
|
"`--remind-after T` is required on every send and controls whether a local follow-up is " + "armed for the same channel, thread, or DM.",
|
|
@@ -9724,7 +9732,6 @@ function criticalRulesSection() {
|
|
|
9724
9732
|
"",
|
|
9725
9733
|
`- **\`${CLI}\` is the only way to communicate.** Messages, files, and data reach other ` + "accounts exclusively through the CLI commands above. Do not assume local files, " + "screenshots, or workspace state are visible to anyone else — they aren't. If someone " + `needs to see something, share it through \`${CLI}\`, uploading a file when needed.`,
|
|
9726
9734
|
"- **Never expose tokens, keys, or secrets.** Redact credential-like strings from tool output " + "before sharing.",
|
|
9727
|
-
"- **Match the sender's language.** Reply in the language they wrote in.",
|
|
9728
9735
|
`- **Leaving a scope is destructive.** Use \`${CLI} channel leave\` or \`${CLI} server leave\` only after your owner explicitly asks you to leave that exact scope.`,
|
|
9729
9736
|
"- **Channel alignment**: you can't send to a channel with unread messages. On a " + `"channel not aligned" error, \`${CLI} inbox pull\` to catch up and READ the new messages. ` + "Judge if your message is still needed or overlaps with what just landed. Adjust or skip; " + "don't mechanically resend."
|
|
9730
9737
|
].join(`
|
|
@@ -9821,6 +9828,7 @@ function workspaceMemorySection(config) {
|
|
|
9821
9828
|
function buildCliSystemPrompt(config) {
|
|
9822
9829
|
const sections = [
|
|
9823
9830
|
identitySection(config),
|
|
9831
|
+
goodMessageContentSection(),
|
|
9824
9832
|
cliCommandsSection(),
|
|
9825
9833
|
messagingSection(),
|
|
9826
9834
|
channelTypesSection(),
|
|
@@ -27394,6 +27402,7 @@ __export(exports_schema, {
|
|
|
27394
27402
|
user: () => user,
|
|
27395
27403
|
taskMessage: () => taskMessage,
|
|
27396
27404
|
session: () => session,
|
|
27405
|
+
nativeOauthAttempt: () => nativeOauthAttempt,
|
|
27397
27406
|
messageFlag: () => messageFlag,
|
|
27398
27407
|
message: () => message,
|
|
27399
27408
|
member: () => member,
|
|
@@ -27420,7 +27429,11 @@ __export(exports_schema, {
|
|
|
27420
27429
|
agentEmailAccount: () => agentEmailAccount,
|
|
27421
27430
|
agentAccess: () => agentAccess,
|
|
27422
27431
|
agent: () => agent,
|
|
27423
|
-
account: () => account
|
|
27432
|
+
account: () => account,
|
|
27433
|
+
NATIVE_OAUTH_STATUSES: () => NATIVE_OAUTH_STATUSES,
|
|
27434
|
+
NATIVE_OAUTH_PROVIDERS: () => NATIVE_OAUTH_PROVIDERS,
|
|
27435
|
+
NATIVE_OAUTH_PLATFORMS: () => NATIVE_OAUTH_PLATFORMS,
|
|
27436
|
+
NATIVE_OAUTH_FAILURE_CODES: () => NATIVE_OAUTH_FAILURE_CODES
|
|
27424
27437
|
});
|
|
27425
27438
|
init_nanoid();
|
|
27426
27439
|
|
|
@@ -27551,6 +27564,119 @@ var verification = sqliteTable("verification", {
|
|
|
27551
27564
|
createdAt: text("createdAt").notNull().$defaultFn(() => new Date().toISOString()),
|
|
27552
27565
|
updatedAt: text("updatedAt").notNull().$defaultFn(() => new Date().toISOString())
|
|
27553
27566
|
});
|
|
27567
|
+
var NATIVE_OAUTH_PROVIDERS = ["github", "google"];
|
|
27568
|
+
var NATIVE_OAUTH_PLATFORMS = [
|
|
27569
|
+
"macos",
|
|
27570
|
+
"windows",
|
|
27571
|
+
"linux",
|
|
27572
|
+
"ios",
|
|
27573
|
+
"android"
|
|
27574
|
+
];
|
|
27575
|
+
var NATIVE_OAUTH_STATUSES = [
|
|
27576
|
+
"pending",
|
|
27577
|
+
"opened",
|
|
27578
|
+
"ready",
|
|
27579
|
+
"exchanging",
|
|
27580
|
+
"consumed",
|
|
27581
|
+
"failed",
|
|
27582
|
+
"cancelled",
|
|
27583
|
+
"replaced"
|
|
27584
|
+
];
|
|
27585
|
+
var NATIVE_OAUTH_FAILURE_CODES = [
|
|
27586
|
+
"access_denied",
|
|
27587
|
+
"provider_error",
|
|
27588
|
+
"oauth_callback_failed",
|
|
27589
|
+
"start_failed",
|
|
27590
|
+
"invalid_handoff"
|
|
27591
|
+
];
|
|
27592
|
+
var nativeOauthAttempt = sqliteTable("native_oauth_attempt", {
|
|
27593
|
+
id: text("id").primaryKey(),
|
|
27594
|
+
instanceKeyHash: text("instance_key_hash").notNull(),
|
|
27595
|
+
stateHash: text("state_hash").notNull(),
|
|
27596
|
+
pkceChallenge: text("pkce_challenge").notNull(),
|
|
27597
|
+
provider: text("provider").$type().notNull(),
|
|
27598
|
+
platform: text("platform").$type().notNull(),
|
|
27599
|
+
redirectPath: text("redirect_path").notNull(),
|
|
27600
|
+
status: text("status").$type().notNull().default("pending"),
|
|
27601
|
+
handoffCodeHash: text("handoff_code_hash"),
|
|
27602
|
+
handoffExpiresAt: integer2("handoff_expires_at"),
|
|
27603
|
+
authKind: text("auth_kind").$type(),
|
|
27604
|
+
failureCode: text("failure_code").$type(),
|
|
27605
|
+
attemptExpiresAt: integer2("attempt_expires_at").notNull(),
|
|
27606
|
+
createdAt: integer2("created_at").notNull(),
|
|
27607
|
+
updatedAt: integer2("updated_at").notNull(),
|
|
27608
|
+
openedAt: integer2("opened_at"),
|
|
27609
|
+
readyAt: integer2("ready_at"),
|
|
27610
|
+
consumedAt: integer2("consumed_at"),
|
|
27611
|
+
failedAt: integer2("failed_at"),
|
|
27612
|
+
cancelledAt: integer2("cancelled_at"),
|
|
27613
|
+
replacedAt: integer2("replaced_at")
|
|
27614
|
+
}, (t) => [
|
|
27615
|
+
index("idx_native_oauth_attempt_instance_status").on(t.instanceKeyHash, t.status),
|
|
27616
|
+
index("idx_native_oauth_attempt_id_status_expiry").on(t.id, t.status, t.attemptExpiresAt),
|
|
27617
|
+
index("idx_native_oauth_attempt_terminal_cleanup").on(t.status, t.updatedAt),
|
|
27618
|
+
uniqueIndex("uq_native_oauth_attempt_instance_live").on(t.instanceKeyHash).where(sql`status IN ('pending', 'opened', 'ready', 'exchanging')`),
|
|
27619
|
+
uniqueIndex("uq_native_oauth_attempt_handoff_hash").on(t.handoffCodeHash).where(sql`handoff_code_hash IS NOT NULL`),
|
|
27620
|
+
check2("ck_native_oauth_attempt_id", sql`length(${t.id}) BETWEEN 22 AND 64 AND ${t.id} NOT GLOB '*[^A-Za-z0-9_-]*'`),
|
|
27621
|
+
check2("ck_native_oauth_attempt_hashes", sql`length(${t.instanceKeyHash}) = 64 AND ${t.instanceKeyHash} NOT GLOB '*[^0-9a-f]*'
|
|
27622
|
+
AND length(${t.stateHash}) = 64 AND ${t.stateHash} NOT GLOB '*[^0-9a-f]*'
|
|
27623
|
+
AND length(${t.pkceChallenge}) = 43 AND ${t.pkceChallenge} NOT GLOB '*[^A-Za-z0-9_-]*'
|
|
27624
|
+
AND (${t.handoffCodeHash} IS NULL OR (length(${t.handoffCodeHash}) = 64 AND ${t.handoffCodeHash} NOT GLOB '*[^0-9a-f]*'))`),
|
|
27625
|
+
check2("ck_native_oauth_attempt_enums", sql`${t.provider} IN ('github', 'google')
|
|
27626
|
+
AND ${t.platform} IN ('macos', 'windows', 'linux', 'ios', 'android')
|
|
27627
|
+
AND ${t.status} IN ('pending', 'opened', 'ready', 'exchanging', 'consumed', 'failed', 'cancelled', 'replaced')
|
|
27628
|
+
AND (${t.authKind} IS NULL OR ${t.authKind} IN ('signin', 'signup'))
|
|
27629
|
+
AND (${t.failureCode} IS NULL OR ${t.failureCode} IN ('access_denied', 'provider_error', 'oauth_callback_failed', 'start_failed', 'invalid_handoff'))`),
|
|
27630
|
+
check2("ck_native_oauth_attempt_redirect", sql`length(${t.redirectPath}) BETWEEN 1 AND 2048
|
|
27631
|
+
AND substr(${t.redirectPath}, 1, 1) = '/'
|
|
27632
|
+
AND substr(${t.redirectPath}, 1, 2) <> '//'
|
|
27633
|
+
AND instr(${t.redirectPath}, char(92)) = 0`),
|
|
27634
|
+
check2("ck_native_oauth_attempt_epochs", sql`typeof(${t.createdAt}) = 'integer' AND ${t.createdAt} BETWEEN 0 AND 9007199254740991
|
|
27635
|
+
AND typeof(${t.updatedAt}) = 'integer' AND ${t.updatedAt} BETWEEN ${t.createdAt} AND 9007199254740991
|
|
27636
|
+
AND typeof(${t.attemptExpiresAt}) = 'integer' AND ${t.attemptExpiresAt} = ${t.createdAt} + 600000
|
|
27637
|
+
AND (${t.handoffExpiresAt} IS NULL OR (typeof(${t.handoffExpiresAt}) = 'integer' AND ${t.handoffExpiresAt} <= ${t.attemptExpiresAt}))`),
|
|
27638
|
+
check2("ck_native_oauth_attempt_state", sql`(
|
|
27639
|
+
${t.status} = 'pending'
|
|
27640
|
+
AND ${t.openedAt} IS NULL AND ${t.readyAt} IS NULL AND ${t.consumedAt} IS NULL
|
|
27641
|
+
AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
27642
|
+
AND ${t.handoffCodeHash} IS NULL AND ${t.handoffExpiresAt} IS NULL
|
|
27643
|
+
AND ${t.authKind} IS NULL AND ${t.failureCode} IS NULL
|
|
27644
|
+
) OR (
|
|
27645
|
+
${t.status} = 'opened'
|
|
27646
|
+
AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NULL AND ${t.consumedAt} IS NULL
|
|
27647
|
+
AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
27648
|
+
AND ${t.handoffCodeHash} IS NULL AND ${t.handoffExpiresAt} IS NULL
|
|
27649
|
+
AND ${t.authKind} IS NULL AND ${t.failureCode} IS NULL
|
|
27650
|
+
) OR (
|
|
27651
|
+
${t.status} IN ('ready', 'exchanging')
|
|
27652
|
+
AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NOT NULL AND ${t.consumedAt} IS NULL
|
|
27653
|
+
AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
27654
|
+
AND ${t.handoffCodeHash} IS NOT NULL AND ${t.handoffExpiresAt} IS NOT NULL
|
|
27655
|
+
AND ${t.handoffExpiresAt} = ${t.readyAt} + 120000
|
|
27656
|
+
AND ${t.authKind} IS NOT NULL AND ${t.failureCode} IS NULL
|
|
27657
|
+
) OR (
|
|
27658
|
+
${t.status} = 'consumed'
|
|
27659
|
+
AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NOT NULL AND ${t.consumedAt} IS NOT NULL
|
|
27660
|
+
AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
27661
|
+
AND ${t.handoffCodeHash} IS NOT NULL AND ${t.handoffExpiresAt} IS NOT NULL
|
|
27662
|
+
AND ${t.authKind} IS NOT NULL AND ${t.failureCode} IS NULL
|
|
27663
|
+
) OR (
|
|
27664
|
+
${t.status} = 'failed'
|
|
27665
|
+
AND ${t.consumedAt} IS NULL AND ${t.failedAt} IS NOT NULL
|
|
27666
|
+
AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
27667
|
+
AND ${t.failureCode} IS NOT NULL
|
|
27668
|
+
) OR (
|
|
27669
|
+
${t.status} = 'cancelled'
|
|
27670
|
+
AND ${t.consumedAt} IS NULL AND ${t.cancelledAt} IS NOT NULL
|
|
27671
|
+
AND ${t.failedAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
27672
|
+
AND ${t.failureCode} IS NULL
|
|
27673
|
+
) OR (
|
|
27674
|
+
${t.status} = 'replaced'
|
|
27675
|
+
AND ${t.consumedAt} IS NULL AND ${t.replacedAt} IS NOT NULL
|
|
27676
|
+
AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL
|
|
27677
|
+
AND ${t.failureCode} IS NULL
|
|
27678
|
+
)`)
|
|
27679
|
+
]);
|
|
27554
27680
|
var workspace = sqliteTable("workspace", {
|
|
27555
27681
|
id: text("id").primaryKey().$defaultFn(() => "sp_" + nanoid3()),
|
|
27556
27682
|
name: text("name").notNull(),
|
|
@@ -29092,12 +29218,20 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
29092
29218
|
const upstream = new URL2(broker.upstreamBaseUrl);
|
|
29093
29219
|
const upstreamClient = upstream.protocol === "https:" ? https : http;
|
|
29094
29220
|
const onPull = options.onInboxPullResponse;
|
|
29221
|
+
const onAck = options.onInboxAckResponse;
|
|
29095
29222
|
const onProxyRequest = options.onProxyRequest;
|
|
29096
29223
|
const reportInboxPullObservationError = (failure) => {
|
|
29097
29224
|
try {
|
|
29098
29225
|
options.onInboxPullObservationError?.(failure);
|
|
29099
29226
|
} catch {}
|
|
29100
29227
|
};
|
|
29228
|
+
const reportInboxAckObservationError = (failure) => {
|
|
29229
|
+
try {
|
|
29230
|
+
options.onInboxAckObservationError?.(failure);
|
|
29231
|
+
} catch {
|
|
29232
|
+
return;
|
|
29233
|
+
}
|
|
29234
|
+
};
|
|
29101
29235
|
const server = http.createServer((req, res) => {
|
|
29102
29236
|
const pathname = new URL2(req.url ?? "/", "http://placeholder").pathname;
|
|
29103
29237
|
if (pathname.startsWith("/__alook/local/")) {
|
|
@@ -29137,8 +29271,11 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
29137
29271
|
}
|
|
29138
29272
|
const reg = verdict.reg;
|
|
29139
29273
|
const isInboxPull = req.method === "POST" && pathname === "/api/community/users/me/inbox/pull";
|
|
29274
|
+
const isInboxAck = req.method === "POST" && pathname === "/api/community/users/me/inbox/ack";
|
|
29140
29275
|
const shouldObserveInboxPull = Boolean(isInboxPull && onPull);
|
|
29276
|
+
const shouldObserveInboxAck = Boolean(isInboxAck && onAck);
|
|
29141
29277
|
let inboxPullObservationToken;
|
|
29278
|
+
let inboxAckObservationToken;
|
|
29142
29279
|
if (shouldObserveInboxPull) {
|
|
29143
29280
|
try {
|
|
29144
29281
|
inboxPullObservationToken = options.onInboxPullStart?.(reg.agentId);
|
|
@@ -29150,6 +29287,17 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
29150
29287
|
});
|
|
29151
29288
|
}
|
|
29152
29289
|
}
|
|
29290
|
+
if (shouldObserveInboxAck) {
|
|
29291
|
+
try {
|
|
29292
|
+
inboxAckObservationToken = options.onInboxAckStart?.(reg.agentId);
|
|
29293
|
+
} catch {
|
|
29294
|
+
reportInboxAckObservationError({
|
|
29295
|
+
agentId: reg.agentId,
|
|
29296
|
+
reason: "observer_failed",
|
|
29297
|
+
contentEncoding: "identity"
|
|
29298
|
+
});
|
|
29299
|
+
}
|
|
29300
|
+
}
|
|
29153
29301
|
if (onProxyRequest) {
|
|
29154
29302
|
try {
|
|
29155
29303
|
const method = req.method ?? "GET";
|
|
@@ -29167,7 +29315,7 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
29167
29315
|
outHeaders[broker.headerNames.agentId.toLowerCase()] = reg.agentId;
|
|
29168
29316
|
outHeaders[broker.headerNames.client.toLowerCase()] = broker.clientLabel;
|
|
29169
29317
|
outHeaders[broker.headerNames.capabilities.toLowerCase()] = [...reg.capabilities].join(",");
|
|
29170
|
-
if (isInboxPull)
|
|
29318
|
+
if (isInboxPull || isInboxAck)
|
|
29171
29319
|
outHeaders["accept-encoding"] = "identity";
|
|
29172
29320
|
let responded = false;
|
|
29173
29321
|
let upstreamRes;
|
|
@@ -29187,43 +29335,72 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
29187
29335
|
};
|
|
29188
29336
|
res_.on("error", destroyResIfIncomplete);
|
|
29189
29337
|
res_.on("close", destroyResIfIncomplete);
|
|
29190
|
-
if (shouldObserveInboxPull && res_.statusCode !== undefined && res_.statusCode >= 200 && res_.statusCode < 300) {
|
|
29338
|
+
if ((shouldObserveInboxPull || shouldObserveInboxAck) && res_.statusCode !== undefined && res_.statusCode >= 200 && res_.statusCode < 300) {
|
|
29191
29339
|
const chunks = [];
|
|
29192
29340
|
res_.on("data", (chunk) => chunks.push(chunk));
|
|
29193
29341
|
res_.on("end", () => {
|
|
29194
29342
|
const body = Buffer.concat(chunks);
|
|
29195
29343
|
const contentEncoding = normalizeContentEncoding(res_.headers["content-encoding"]);
|
|
29196
29344
|
if (contentEncoding !== "identity") {
|
|
29197
|
-
|
|
29198
|
-
|
|
29199
|
-
|
|
29200
|
-
|
|
29201
|
-
|
|
29345
|
+
if (shouldObserveInboxPull) {
|
|
29346
|
+
reportInboxPullObservationError({
|
|
29347
|
+
agentId: reg.agentId,
|
|
29348
|
+
reason: "unexpected_content_encoding",
|
|
29349
|
+
contentEncoding
|
|
29350
|
+
});
|
|
29351
|
+
} else {
|
|
29352
|
+
reportInboxAckObservationError({
|
|
29353
|
+
agentId: reg.agentId,
|
|
29354
|
+
reason: "unexpected_content_encoding",
|
|
29355
|
+
contentEncoding
|
|
29356
|
+
});
|
|
29357
|
+
}
|
|
29202
29358
|
} else {
|
|
29203
29359
|
let parsed;
|
|
29204
29360
|
try {
|
|
29205
29361
|
parsed = JSON.parse(body.toString("utf8"));
|
|
29206
29362
|
} catch {
|
|
29207
|
-
|
|
29208
|
-
agentId: reg.agentId,
|
|
29209
|
-
|
|
29210
|
-
contentEncoding
|
|
29211
|
-
}
|
|
29363
|
+
if (shouldObserveInboxPull) {
|
|
29364
|
+
reportInboxPullObservationError({ agentId: reg.agentId, reason: "invalid_json", contentEncoding });
|
|
29365
|
+
} else {
|
|
29366
|
+
reportInboxAckObservationError({ agentId: reg.agentId, reason: "invalid_json", contentEncoding });
|
|
29367
|
+
}
|
|
29212
29368
|
}
|
|
29213
29369
|
if (parsed !== undefined) {
|
|
29214
|
-
if (
|
|
29215
|
-
|
|
29370
|
+
if (shouldObserveInboxPull) {
|
|
29371
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || !Array.isArray(parsed.messages)) {
|
|
29372
|
+
reportInboxPullObservationError({
|
|
29373
|
+
agentId: reg.agentId,
|
|
29374
|
+
reason: "invalid_inbox_shape",
|
|
29375
|
+
contentEncoding
|
|
29376
|
+
});
|
|
29377
|
+
} else {
|
|
29378
|
+
const messages = parsed.messages;
|
|
29379
|
+
if (messages.length > 0) {
|
|
29380
|
+
try {
|
|
29381
|
+
onPull(reg.agentId, messages, inboxPullObservationToken);
|
|
29382
|
+
} catch {
|
|
29383
|
+
reportInboxPullObservationError({
|
|
29384
|
+
agentId: reg.agentId,
|
|
29385
|
+
reason: "observer_failed",
|
|
29386
|
+
contentEncoding
|
|
29387
|
+
});
|
|
29388
|
+
}
|
|
29389
|
+
}
|
|
29390
|
+
}
|
|
29391
|
+
} else if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || !Array.isArray(parsed.applied) || !parsed.applied.every((cursor) => Boolean(cursor) && typeof cursor === "object" && !Array.isArray(cursor) && typeof cursor.channel === "string" && cursor.channel.length > 0 && typeof cursor.seq === "number" && Number.isSafeInteger(cursor.seq) && cursor.seq > 0)) {
|
|
29392
|
+
reportInboxAckObservationError({
|
|
29216
29393
|
agentId: reg.agentId,
|
|
29217
|
-
reason: "
|
|
29394
|
+
reason: "invalid_ack_shape",
|
|
29218
29395
|
contentEncoding
|
|
29219
29396
|
});
|
|
29220
29397
|
} else {
|
|
29221
|
-
const
|
|
29222
|
-
if (
|
|
29398
|
+
const applied = parsed.applied;
|
|
29399
|
+
if (applied.length > 0) {
|
|
29223
29400
|
try {
|
|
29224
|
-
|
|
29401
|
+
onAck(reg.agentId, applied, inboxAckObservationToken);
|
|
29225
29402
|
} catch {
|
|
29226
|
-
|
|
29403
|
+
reportInboxAckObservationError({
|
|
29227
29404
|
agentId: reg.agentId,
|
|
29228
29405
|
reason: "observer_failed",
|
|
29229
29406
|
contentEncoding
|
|
@@ -31006,6 +31183,15 @@ function createLogger2(opts) {
|
|
|
31006
31183
|
|
|
31007
31184
|
// ../shared/src/db/queries/_chunk.ts
|
|
31008
31185
|
var D1_MAX_BIND_PARAMS = 100;
|
|
31186
|
+
function maxInParams(fixedParams) {
|
|
31187
|
+
if (!Number.isInteger(fixedParams) || fixedParams < 0) {
|
|
31188
|
+
throw new Error("fixed params must be a non-negative integer");
|
|
31189
|
+
}
|
|
31190
|
+
if (fixedParams >= D1_MAX_BIND_PARAMS) {
|
|
31191
|
+
throw new Error("fixed params must leave room for at least one IN parameter");
|
|
31192
|
+
}
|
|
31193
|
+
return D1_MAX_BIND_PARAMS - fixedParams;
|
|
31194
|
+
}
|
|
31009
31195
|
function maxRowsPerInsert(paramsPerRow) {
|
|
31010
31196
|
if (paramsPerRow < 1)
|
|
31011
31197
|
throw new Error("paramsPerRow must be >= 1");
|
|
@@ -31097,6 +31283,7 @@ var AGENT_MESSAGE_COLUMNS = {
|
|
|
31097
31283
|
replyToId: communityMessage.replyToId
|
|
31098
31284
|
};
|
|
31099
31285
|
var channelJoinBaselineGuard = sql`${communityMessage.createdAt} > COALESCE(${communityChannelMember.addedAt}, ${communityServerMember.joinedAt}, '')`;
|
|
31286
|
+
var AGENT_UNREAD_CHANNEL_CHUNK_SIZE = maxInParams(13);
|
|
31100
31287
|
|
|
31101
31288
|
// ../shared/src/db/queries/community/mention.ts
|
|
31102
31289
|
var MENTION_INSERT_MAX_ROWS = maxRowsPerInsert(5);
|
|
@@ -31709,6 +31896,10 @@ var serverRailCommandSchema = exports_external.discriminatedUnion("kind", [
|
|
|
31709
31896
|
var serverRailCommitRequestSchema = exports_external.strictObject({
|
|
31710
31897
|
commands: exports_external.array(serverRailCommandSchema).min(1).max(MAX_SERVER_RAIL_COMMANDS)
|
|
31711
31898
|
});
|
|
31899
|
+
// ../shared/src/db/queries/native-oauth.ts
|
|
31900
|
+
var ATTEMPT_TTL_MS = 10 * 60 * 1000;
|
|
31901
|
+
var HANDOFF_TTL_MS = 2 * 60 * 1000;
|
|
31902
|
+
var RETENTION_MS = 24 * 60 * 60 * 1000;
|
|
31712
31903
|
// ../shared/src/db/queries/task.ts
|
|
31713
31904
|
var DEFAULT_STALE_SECONDS = Number(process.env.ALOOK_STALE_DISPATCH_TIMEOUT_S) || 20;
|
|
31714
31905
|
var DEFAULT_STALE_RUNNING_SECONDS = Number(process.env.ALOOK_STALE_RUNNING_TIMEOUT_S) || 3600;
|
|
@@ -31737,6 +31928,80 @@ var FTS_KEYWORDS = new Set(["and", "or", "not", "near"]);
|
|
|
31737
31928
|
var FOLDER_ITEM_INSERT_MAX_ROWS = maxRowsPerInsert(3);
|
|
31738
31929
|
// ../shared/src/db/queries/community/diagnostic-report.ts
|
|
31739
31930
|
var diagnosticOwner = alias(user, "diagnostic_owner");
|
|
31931
|
+
// ../shared/src/lib/safe-redirect.ts
|
|
31932
|
+
var MAX_REDIRECT_BYTES = 2048;
|
|
31933
|
+
var CONTROL_CHARACTERS = /[\u0000-\u001f\u007f]/;
|
|
31934
|
+
function isSafeCandidate(value) {
|
|
31935
|
+
return value.startsWith("/") && !value.startsWith("//") && !value.includes("\\") && !value.includes("#") && !CONTROL_CHARACTERS.test(value);
|
|
31936
|
+
}
|
|
31937
|
+
function isSafeRedirectPath(value) {
|
|
31938
|
+
if (new TextEncoder().encode(value).byteLength > MAX_REDIRECT_BYTES)
|
|
31939
|
+
return false;
|
|
31940
|
+
if (!isSafeCandidate(value))
|
|
31941
|
+
return false;
|
|
31942
|
+
let decoded = value;
|
|
31943
|
+
for (let depth = 0;depth < 8; depth += 1) {
|
|
31944
|
+
let next;
|
|
31945
|
+
try {
|
|
31946
|
+
next = decodeURIComponent(decoded);
|
|
31947
|
+
} catch {
|
|
31948
|
+
return depth > 0;
|
|
31949
|
+
}
|
|
31950
|
+
if (next === decoded)
|
|
31951
|
+
break;
|
|
31952
|
+
if (!isSafeCandidate(next))
|
|
31953
|
+
return false;
|
|
31954
|
+
decoded = next;
|
|
31955
|
+
if (depth === 7)
|
|
31956
|
+
return false;
|
|
31957
|
+
}
|
|
31958
|
+
try {
|
|
31959
|
+
const base = new URL("https://alook.invalid");
|
|
31960
|
+
const resolved = new URL(value, base);
|
|
31961
|
+
return resolved.origin === base.origin;
|
|
31962
|
+
} catch {
|
|
31963
|
+
return false;
|
|
31964
|
+
}
|
|
31965
|
+
}
|
|
31966
|
+
|
|
31967
|
+
// ../shared/src/lib/native-oauth-contract.ts
|
|
31968
|
+
var ATTEMPT_ID = /^[A-Za-z0-9_-]{22,64}$/;
|
|
31969
|
+
var SHA256_HEX = /^[0-9a-f]{64}$/;
|
|
31970
|
+
var BASE64URL_32_BYTES = /^[A-Za-z0-9_-]{43}$/;
|
|
31971
|
+
var HANDOFF_CODE = /^[A-Za-z0-9_-]{32,128}$/;
|
|
31972
|
+
var nativeOauthProviderSchema = exports_external.enum(["github", "google"]);
|
|
31973
|
+
var nativeOauthPlatformSchema = exports_external.enum([
|
|
31974
|
+
"macos",
|
|
31975
|
+
"windows",
|
|
31976
|
+
"linux",
|
|
31977
|
+
"ios",
|
|
31978
|
+
"android"
|
|
31979
|
+
]);
|
|
31980
|
+
var nativeOauthAttemptIdSchema = exports_external.string().regex(ATTEMPT_ID);
|
|
31981
|
+
var nativeOauthHandoffCodeSchema = exports_external.string().regex(HANDOFF_CODE);
|
|
31982
|
+
var nativeOauthFailureCodeSchema = exports_external.enum([
|
|
31983
|
+
"access_denied",
|
|
31984
|
+
"provider_error",
|
|
31985
|
+
"oauth_callback_failed",
|
|
31986
|
+
"start_failed",
|
|
31987
|
+
"invalid_handoff"
|
|
31988
|
+
]);
|
|
31989
|
+
var nativeOauthRegistrationSchema = exports_external.object({
|
|
31990
|
+
attemptId: nativeOauthAttemptIdSchema,
|
|
31991
|
+
stateHash: exports_external.string().regex(SHA256_HEX),
|
|
31992
|
+
codeChallenge: exports_external.string().regex(BASE64URL_32_BYTES),
|
|
31993
|
+
instanceKeyHash: exports_external.string().regex(SHA256_HEX),
|
|
31994
|
+
platform: nativeOauthPlatformSchema,
|
|
31995
|
+
provider: nativeOauthProviderSchema,
|
|
31996
|
+
redirectPath: exports_external.string().refine(isSafeRedirectPath)
|
|
31997
|
+
}).strict();
|
|
31998
|
+
var nativeOauthExchangeSchema = exports_external.object({
|
|
31999
|
+
attemptId: nativeOauthAttemptIdSchema,
|
|
32000
|
+
state: exports_external.string().regex(BASE64URL_32_BYTES),
|
|
32001
|
+
verifier: exports_external.string().regex(BASE64URL_32_BYTES),
|
|
32002
|
+
code: nativeOauthHandoffCodeSchema
|
|
32003
|
+
}).strict();
|
|
32004
|
+
var nativeOauthProofSchema = nativeOauthExchangeSchema.omit({ code: true }).strict();
|
|
31740
32005
|
// src/manager/wakeCoordinator.ts
|
|
31741
32006
|
class WakeCoordinator {
|
|
31742
32007
|
agents = new Map;
|
|
@@ -34520,19 +34785,24 @@ async function createDaemon(opts) {
|
|
|
34520
34785
|
const broker = new CredentialBroker({ upstreamBaseUrl: opts.serverUrl });
|
|
34521
34786
|
const proxy = await startCredentialProxy(broker, {
|
|
34522
34787
|
onInboxPullStart: (agentId) => ({
|
|
34523
|
-
modelSeenGeneration: channelRef?.modelSeenGeneration(agentId),
|
|
34524
34788
|
owner: managerRef?.timelineTurnOwner(agentId) ?? null
|
|
34525
34789
|
}),
|
|
34526
34790
|
onInboxPullResponse: (agentId, messages, observationToken) => {
|
|
34527
34791
|
const token = observationToken && typeof observationToken === "object" ? observationToken : null;
|
|
34528
34792
|
timeline2.recordInboxPull(agentId, token?.owner ?? null, messages);
|
|
34529
|
-
if (typeof token?.modelSeenGeneration === "number") {
|
|
34530
|
-
channelRef?.recordModelSeen(agentId, messages, token.modelSeenGeneration);
|
|
34531
|
-
}
|
|
34532
34793
|
},
|
|
34533
34794
|
onInboxPullObservationError: ({ agentId, reason, contentEncoding }) => {
|
|
34534
34795
|
log2.warn("inbox pull timeline observation failed", { agentId, reason, contentEncoding });
|
|
34535
34796
|
},
|
|
34797
|
+
onInboxAckStart: (agentId) => channelRef?.modelSeenGeneration(agentId),
|
|
34798
|
+
onInboxAckResponse: (agentId, applied, observationToken) => {
|
|
34799
|
+
if (typeof observationToken !== "number")
|
|
34800
|
+
return;
|
|
34801
|
+
channelRef?.recordModelSeen(agentId, applied.map((cursor) => ({ channel: cursor.channel, seq: `#${cursor.seq}` })), observationToken);
|
|
34802
|
+
},
|
|
34803
|
+
onInboxAckObservationError: ({ agentId, reason, contentEncoding }) => {
|
|
34804
|
+
log2.warn("inbox ack observation failed", { agentId, reason, contentEncoding });
|
|
34805
|
+
},
|
|
34536
34806
|
onMessageReminderArm: (input) => reminderSchedulerRef?.arm(input) ?? { armed: false, reason: "reminder_scheduler_unavailable" },
|
|
34537
34807
|
onProxyRequest: (agentId, method, pathname, metadata) => {
|
|
34538
34808
|
const subcommand = deriveAuditLogSubcommand(pathname, method);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alook/daemon",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.33",
|
|
4
4
|
"description": "Alook agent daemon — host-side runtime backend, process manager, credential proxy, and control plane.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/alookai/alook#readme",
|