@alook/daemon 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/cli/index.js +1295 -235
- package/dist/index.js +1127 -152
- 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
|
|
|
@@ -15979,6 +15984,7 @@ var TERMINAL_MEETING_STATUSES = [
|
|
|
15979
15984
|
MeetingStatus.COMPLETED,
|
|
15980
15985
|
MeetingStatus.FAILED
|
|
15981
15986
|
];
|
|
15987
|
+
var COMMUNITY_BOT_LIMIT_PER_OWNER = 20;
|
|
15982
15988
|
var COMMUNITY_BOT_NAME_MIN = 1;
|
|
15983
15989
|
var COMMUNITY_BOT_NAME_MAX = 32;
|
|
15984
15990
|
var COMMUNITY_BOT_DESCRIPTION_MAX = 1024;
|
|
@@ -16044,6 +16050,119 @@ var verification = sqliteTable("verification", {
|
|
|
16044
16050
|
createdAt: text("createdAt").notNull().$defaultFn(() => new Date().toISOString()),
|
|
16045
16051
|
updatedAt: text("updatedAt").notNull().$defaultFn(() => new Date().toISOString())
|
|
16046
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
|
+
]);
|
|
16047
16166
|
var workspace = sqliteTable("workspace", {
|
|
16048
16167
|
id: text("id").primaryKey().$defaultFn(() => "sp_" + nanoid3()),
|
|
16049
16168
|
name: text("name").notNull(),
|
|
@@ -16853,6 +16972,13 @@ var HostCommandSchema = exports_external.discriminatedUnion("type", [
|
|
|
16853
16972
|
launchId: exports_external.string().min(1),
|
|
16854
16973
|
unreadNotice: exports_external.unknown()
|
|
16855
16974
|
}),
|
|
16975
|
+
exports_external.object({
|
|
16976
|
+
type: exports_external.literal("agent:event"),
|
|
16977
|
+
agentId: exports_external.string().min(1),
|
|
16978
|
+
config: exports_external.unknown(),
|
|
16979
|
+
launchId: exports_external.string().min(1),
|
|
16980
|
+
prompt: exports_external.string().min(1).max(32768)
|
|
16981
|
+
}),
|
|
16856
16982
|
exports_external.object({
|
|
16857
16983
|
type: exports_external.literal("agent:stop"),
|
|
16858
16984
|
agentId: exports_external.string().min(1)
|
|
@@ -17762,6 +17888,10 @@ var CommunityBotPatchRequestSchema = exports_external.object({
|
|
|
17762
17888
|
var CommunityBotAddToServerRequestSchema = exports_external.object({
|
|
17763
17889
|
botId: exports_external.string().min(1)
|
|
17764
17890
|
});
|
|
17891
|
+
var CommunityServerOnboardRequestSchema = exports_external.strictObject({
|
|
17892
|
+
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"),
|
|
17893
|
+
wakePrompt: exports_external.string().max(32768).refine((value) => value.trim().length > 0, "wakePrompt is required")
|
|
17894
|
+
});
|
|
17765
17895
|
var CommunityAgentMessageContentSchema = exports_external.object({ text: exports_external.string().max(MAX_MESSAGE_CONTENT_LENGTH).default("") }).catchall(exports_external.unknown());
|
|
17766
17896
|
var CommunityAgentSeqSchema = exports_external.number().int().min(0);
|
|
17767
17897
|
var CommunityAgentPositiveSeqSchema = exports_external.number().int().min(1);
|
|
@@ -18365,6 +18495,15 @@ function createLogger(opts) {
|
|
|
18365
18495
|
|
|
18366
18496
|
// ../shared/src/db/queries/_chunk.ts
|
|
18367
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
|
+
}
|
|
18368
18507
|
function maxRowsPerInsert(paramsPerRow) {
|
|
18369
18508
|
if (paramsPerRow < 1)
|
|
18370
18509
|
throw new Error("paramsPerRow must be >= 1");
|
|
@@ -18456,6 +18595,7 @@ var AGENT_MESSAGE_COLUMNS = {
|
|
|
18456
18595
|
replyToId: communityMessage.replyToId
|
|
18457
18596
|
};
|
|
18458
18597
|
var channelJoinBaselineGuard = sql`${communityMessage.createdAt} > COALESCE(${communityChannelMember.addedAt}, ${communityServerMember.joinedAt}, '')`;
|
|
18598
|
+
var AGENT_UNREAD_CHANNEL_CHUNK_SIZE = maxInParams(13);
|
|
18459
18599
|
|
|
18460
18600
|
// ../shared/src/db/queries/community/mention.ts
|
|
18461
18601
|
var MENTION_INSERT_MAX_ROWS = maxRowsPerInsert(5);
|
|
@@ -19068,6 +19208,10 @@ var serverRailCommandSchema = exports_external.discriminatedUnion("kind", [
|
|
|
19068
19208
|
var serverRailCommitRequestSchema = exports_external.strictObject({
|
|
19069
19209
|
commands: exports_external.array(serverRailCommandSchema).min(1).max(MAX_SERVER_RAIL_COMMANDS)
|
|
19070
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;
|
|
19071
19215
|
// ../shared/src/db/queries/task.ts
|
|
19072
19216
|
var DEFAULT_STALE_SECONDS = Number(process.env.ALOOK_STALE_DISPATCH_TIMEOUT_S) || 20;
|
|
19073
19217
|
var DEFAULT_STALE_RUNNING_SECONDS = Number(process.env.ALOOK_STALE_RUNNING_TIMEOUT_S) || 3600;
|
|
@@ -19108,6 +19252,80 @@ function parseInviteToken(input) {
|
|
|
19108
19252
|
return urlMatch[1];
|
|
19109
19253
|
return BARE_TOKEN_RE.test(trimmed) ? trimmed : null;
|
|
19110
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();
|
|
19111
19329
|
// ../shared/src/semver.ts
|
|
19112
19330
|
var RELEASE_VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
19113
19331
|
function parseReleaseVersion(value) {
|
|
@@ -19557,13 +19775,13 @@ function createProxyServerApi(config2) {
|
|
|
19557
19775
|
|
|
19558
19776
|
// src/cli/daemonStart.ts
|
|
19559
19777
|
import * as fs12 from "fs";
|
|
19560
|
-
import * as
|
|
19778
|
+
import * as path17 from "path";
|
|
19561
19779
|
import * as crypto5 from "crypto";
|
|
19562
19780
|
import * as os3 from "os";
|
|
19563
|
-
import { homedir as
|
|
19781
|
+
import { homedir as homedir8 } from "os";
|
|
19564
19782
|
|
|
19565
19783
|
// src/discovery.ts
|
|
19566
|
-
import * as
|
|
19784
|
+
import * as path13 from "path";
|
|
19567
19785
|
import * as fs6 from "fs";
|
|
19568
19786
|
import { fileURLToPath } from "url";
|
|
19569
19787
|
// agent-driver/dist/host/default-host.js
|
|
@@ -20707,6 +20925,12 @@ function tryParseJsonLine(line) {
|
|
|
20707
20925
|
return null;
|
|
20708
20926
|
}
|
|
20709
20927
|
}
|
|
20928
|
+
function asRecord(value) {
|
|
20929
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
20930
|
+
}
|
|
20931
|
+
function tryParseJsonRecord(line) {
|
|
20932
|
+
return asRecord(tryParseJsonLine(line));
|
|
20933
|
+
}
|
|
20710
20934
|
|
|
20711
20935
|
// agent-driver/dist/adapters/claude/normalizer.js
|
|
20712
20936
|
var API_ERROR_RE = /API Error:.*(?:Connection error|\b[45]\d{2}\b)/i;
|
|
@@ -21205,6 +21429,241 @@ class ClaudeTurnProtocol {
|
|
|
21205
21429
|
}
|
|
21206
21430
|
}
|
|
21207
21431
|
|
|
21432
|
+
// agent-driver/dist/adapters/claude/recent-context.js
|
|
21433
|
+
import { createReadStream as createReadStream2 } from "node:fs";
|
|
21434
|
+
import { homedir } from "node:os";
|
|
21435
|
+
import path7 from "node:path";
|
|
21436
|
+
import { createInterface } from "node:readline";
|
|
21437
|
+
|
|
21438
|
+
// agent-driver/dist/internal/recent-context.js
|
|
21439
|
+
import path6 from "node:path";
|
|
21440
|
+
import { createReadStream } from "node:fs";
|
|
21441
|
+
import { readdir, stat } from "node:fs/promises";
|
|
21442
|
+
function normalizeAbsolutePath(value) {
|
|
21443
|
+
if (typeof value !== "string" || !path6.isAbsolute(value))
|
|
21444
|
+
return null;
|
|
21445
|
+
return path6.normalize(value);
|
|
21446
|
+
}
|
|
21447
|
+
function normalizeModifiedAt(value) {
|
|
21448
|
+
const date5 = value instanceof Date ? value : typeof value === "string" || typeof value === "number" ? new Date(value) : null;
|
|
21449
|
+
if (!date5 || !Number.isFinite(date5.getTime()))
|
|
21450
|
+
return null;
|
|
21451
|
+
return date5.toISOString();
|
|
21452
|
+
}
|
|
21453
|
+
function isValidRecentContextTopK(value) {
|
|
21454
|
+
return Number.isSafeInteger(value) && value >= 0;
|
|
21455
|
+
}
|
|
21456
|
+
function isMissingPathError(error51) {
|
|
21457
|
+
return error51?.code === "ENOENT";
|
|
21458
|
+
}
|
|
21459
|
+
async function readFirstLine(filePath, maxBytes = 65536) {
|
|
21460
|
+
const stream = createReadStream(filePath, { highWaterMark: 1 });
|
|
21461
|
+
const bytes = [];
|
|
21462
|
+
let length = 0;
|
|
21463
|
+
try {
|
|
21464
|
+
for await (const chunk2 of stream) {
|
|
21465
|
+
const byte = Buffer.isBuffer(chunk2) ? chunk2 : Buffer.from(chunk2);
|
|
21466
|
+
if (byte[0] === 10)
|
|
21467
|
+
break;
|
|
21468
|
+
if (length >= maxBytes)
|
|
21469
|
+
return null;
|
|
21470
|
+
bytes.push(byte);
|
|
21471
|
+
length += byte.length;
|
|
21472
|
+
}
|
|
21473
|
+
return length === 0 ? null : Buffer.concat(bytes, length).toString("utf8").replace(/\r$/, "");
|
|
21474
|
+
} catch (error51) {
|
|
21475
|
+
if (isMissingPathError(error51))
|
|
21476
|
+
return null;
|
|
21477
|
+
throw error51;
|
|
21478
|
+
} finally {
|
|
21479
|
+
stream.destroy();
|
|
21480
|
+
}
|
|
21481
|
+
}
|
|
21482
|
+
async function collectJsonlFileCandidates(root, options = {}) {
|
|
21483
|
+
const candidates = [];
|
|
21484
|
+
const readDirectory = options.readDirectory ?? ((directory) => readdir(directory, { withFileTypes: true }));
|
|
21485
|
+
const statPath = options.statPath ?? stat;
|
|
21486
|
+
const visit = async (directory, remainingDepth, includeFiles) => {
|
|
21487
|
+
let entries;
|
|
21488
|
+
try {
|
|
21489
|
+
entries = await readDirectory(directory);
|
|
21490
|
+
} catch (error51) {
|
|
21491
|
+
if (isMissingPathError(error51))
|
|
21492
|
+
return;
|
|
21493
|
+
throw error51;
|
|
21494
|
+
}
|
|
21495
|
+
await Promise.all(entries.map(async (entry) => {
|
|
21496
|
+
const entryPath = path6.join(directory, entry.name);
|
|
21497
|
+
if (entry.isDirectory() && remainingDepth > 0) {
|
|
21498
|
+
await visit(entryPath, remainingDepth - 1, true);
|
|
21499
|
+
} else if (includeFiles && entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
21500
|
+
try {
|
|
21501
|
+
const metadata = await statPath(entryPath);
|
|
21502
|
+
if (metadata.isFile())
|
|
21503
|
+
candidates.push({ filePath: entryPath, modifiedAt: metadata.mtime });
|
|
21504
|
+
} catch (error51) {
|
|
21505
|
+
if (!isMissingPathError(error51))
|
|
21506
|
+
throw error51;
|
|
21507
|
+
}
|
|
21508
|
+
}
|
|
21509
|
+
}));
|
|
21510
|
+
};
|
|
21511
|
+
await visit(root, options.maxDepth ?? Number.POSITIVE_INFINITY, options.includeRootFiles ?? true);
|
|
21512
|
+
return candidates;
|
|
21513
|
+
}
|
|
21514
|
+
function retainNewest(values, key, value, topK) {
|
|
21515
|
+
const existing = values.get(key);
|
|
21516
|
+
if (existing) {
|
|
21517
|
+
if (value.modifiedAt > existing.modifiedAt)
|
|
21518
|
+
values.set(key, value);
|
|
21519
|
+
return;
|
|
21520
|
+
}
|
|
21521
|
+
if (values.size < topK) {
|
|
21522
|
+
values.set(key, value);
|
|
21523
|
+
return;
|
|
21524
|
+
}
|
|
21525
|
+
let oldest;
|
|
21526
|
+
for (const entry of values) {
|
|
21527
|
+
if (!oldest || entry[1].modifiedAt < oldest[1].modifiedAt)
|
|
21528
|
+
oldest = entry;
|
|
21529
|
+
}
|
|
21530
|
+
if (oldest && value.modifiedAt > oldest[1].modifiedAt) {
|
|
21531
|
+
values.delete(oldest[0]);
|
|
21532
|
+
values.set(key, value);
|
|
21533
|
+
}
|
|
21534
|
+
}
|
|
21535
|
+
|
|
21536
|
+
class RecentContextCollector {
|
|
21537
|
+
request;
|
|
21538
|
+
sessionFileCapability;
|
|
21539
|
+
sessions = new Map;
|
|
21540
|
+
projects = new Map;
|
|
21541
|
+
constructor(request, sessionFileCapability) {
|
|
21542
|
+
this.request = request;
|
|
21543
|
+
this.sessionFileCapability = sessionFileCapability;
|
|
21544
|
+
}
|
|
21545
|
+
add(candidate, target2 = "both") {
|
|
21546
|
+
const projectPath = normalizeAbsolutePath(candidate.projectPath);
|
|
21547
|
+
const modifiedAt = normalizeModifiedAt(candidate.modifiedAt);
|
|
21548
|
+
if (!projectPath || !modifiedAt)
|
|
21549
|
+
return;
|
|
21550
|
+
if (target2 !== "session") {
|
|
21551
|
+
retainNewest(this.projects, projectPath, { projectPath, modifiedAt }, this.request.recentProjectsTopK);
|
|
21552
|
+
}
|
|
21553
|
+
if (target2 === "project" || this.sessionFileCapability !== "supported")
|
|
21554
|
+
return;
|
|
21555
|
+
const sessionFilePath = normalizeAbsolutePath(candidate.sessionFilePath);
|
|
21556
|
+
if (!sessionFilePath)
|
|
21557
|
+
return;
|
|
21558
|
+
retainNewest(this.sessions, sessionFilePath, { sessionFilePath, projectPath, modifiedAt }, this.request.recentSessionFilesTopK);
|
|
21559
|
+
}
|
|
21560
|
+
get satisfied() {
|
|
21561
|
+
const sessionsSatisfied = this.sessionFileCapability === "unavailable" || this.sessions.size >= this.request.recentSessionFilesTopK;
|
|
21562
|
+
return sessionsSatisfied && this.projects.size >= this.request.recentProjectsTopK;
|
|
21563
|
+
}
|
|
21564
|
+
result() {
|
|
21565
|
+
const newestFirst = (left, right) => right.modifiedAt.localeCompare(left.modifiedAt);
|
|
21566
|
+
return {
|
|
21567
|
+
sessionFiles: {
|
|
21568
|
+
capability: this.sessionFileCapability,
|
|
21569
|
+
items: [...this.sessions.values()].sort(newestFirst).slice(0, this.request.recentSessionFilesTopK)
|
|
21570
|
+
},
|
|
21571
|
+
recentProjects: [...this.projects.values()].sort(newestFirst).slice(0, this.request.recentProjectsTopK)
|
|
21572
|
+
};
|
|
21573
|
+
}
|
|
21574
|
+
}
|
|
21575
|
+
function sanitizeRecentContextData(value, request) {
|
|
21576
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
21577
|
+
return null;
|
|
21578
|
+
const candidate = value;
|
|
21579
|
+
if (!candidate.sessionFiles || typeof candidate.sessionFiles !== "object" || Array.isArray(candidate.sessionFiles)) {
|
|
21580
|
+
return null;
|
|
21581
|
+
}
|
|
21582
|
+
const sessionFiles = candidate.sessionFiles;
|
|
21583
|
+
const capability = sessionFiles.capability;
|
|
21584
|
+
if (capability !== "supported" && capability !== "unavailable" || !Array.isArray(sessionFiles.items)) {
|
|
21585
|
+
return null;
|
|
21586
|
+
}
|
|
21587
|
+
if (!Array.isArray(candidate.recentProjects))
|
|
21588
|
+
return null;
|
|
21589
|
+
const collector = new RecentContextCollector(request, capability);
|
|
21590
|
+
if (capability === "supported") {
|
|
21591
|
+
for (const item of sessionFiles.items) {
|
|
21592
|
+
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
21593
|
+
continue;
|
|
21594
|
+
const record2 = item;
|
|
21595
|
+
collector.add({
|
|
21596
|
+
sessionFilePath: record2.sessionFilePath,
|
|
21597
|
+
projectPath: record2.projectPath,
|
|
21598
|
+
modifiedAt: record2.modifiedAt
|
|
21599
|
+
}, "session");
|
|
21600
|
+
}
|
|
21601
|
+
}
|
|
21602
|
+
for (const item of candidate.recentProjects) {
|
|
21603
|
+
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
21604
|
+
continue;
|
|
21605
|
+
const record2 = item;
|
|
21606
|
+
collector.add({ projectPath: record2.projectPath, modifiedAt: record2.modifiedAt }, "project");
|
|
21607
|
+
}
|
|
21608
|
+
return collector.result();
|
|
21609
|
+
}
|
|
21610
|
+
|
|
21611
|
+
// agent-driver/dist/adapters/claude/recent-context.js
|
|
21612
|
+
async function readClaudeProjectPath(filePath) {
|
|
21613
|
+
const input = createReadStream2(filePath);
|
|
21614
|
+
const lines = createInterface({ input, crlfDelay: Infinity });
|
|
21615
|
+
try {
|
|
21616
|
+
for await (const line of lines) {
|
|
21617
|
+
let record2;
|
|
21618
|
+
try {
|
|
21619
|
+
record2 = JSON.parse(line);
|
|
21620
|
+
} catch {
|
|
21621
|
+
continue;
|
|
21622
|
+
}
|
|
21623
|
+
if (!record2 || typeof record2 !== "object")
|
|
21624
|
+
continue;
|
|
21625
|
+
const cwd = record2.cwd;
|
|
21626
|
+
if (typeof cwd === "string" && path7.isAbsolute(cwd))
|
|
21627
|
+
return cwd;
|
|
21628
|
+
}
|
|
21629
|
+
return null;
|
|
21630
|
+
} catch (error51) {
|
|
21631
|
+
if (isMissingPathError(error51))
|
|
21632
|
+
return null;
|
|
21633
|
+
throw error51;
|
|
21634
|
+
} finally {
|
|
21635
|
+
lines.close();
|
|
21636
|
+
input.destroy();
|
|
21637
|
+
}
|
|
21638
|
+
}
|
|
21639
|
+
async function discoverClaudeRecentContext(request, dependencies = {}) {
|
|
21640
|
+
const collector = new RecentContextCollector(request, "supported");
|
|
21641
|
+
if (collector.satisfied)
|
|
21642
|
+
return collector.result();
|
|
21643
|
+
const projectsRoot = path7.resolve(dependencies.projectsRoot ?? path7.join(process.env.CLAUDE_CONFIG_DIR || path7.join(homedir(), ".claude"), "projects"));
|
|
21644
|
+
const readProjectPath = dependencies.readProjectPath ?? readClaudeProjectPath;
|
|
21645
|
+
const candidates = await collectJsonlFileCandidates(projectsRoot, {
|
|
21646
|
+
includeRootFiles: false,
|
|
21647
|
+
maxDepth: 1,
|
|
21648
|
+
readDirectory: dependencies.readDirectory,
|
|
21649
|
+
statPath: dependencies.statPath
|
|
21650
|
+
});
|
|
21651
|
+
candidates.sort((left, right) => right.modifiedAt.getTime() - left.modifiedAt.getTime());
|
|
21652
|
+
for (const candidate of candidates) {
|
|
21653
|
+
const projectPath = await readProjectPath(candidate.filePath);
|
|
21654
|
+
if (!projectPath)
|
|
21655
|
+
continue;
|
|
21656
|
+
collector.add({
|
|
21657
|
+
sessionFilePath: candidate.filePath,
|
|
21658
|
+
projectPath,
|
|
21659
|
+
modifiedAt: candidate.modifiedAt
|
|
21660
|
+
});
|
|
21661
|
+
if (collector.satisfied)
|
|
21662
|
+
break;
|
|
21663
|
+
}
|
|
21664
|
+
return collector.result();
|
|
21665
|
+
}
|
|
21666
|
+
|
|
21208
21667
|
// agent-driver/dist/adapters/claude/index.js
|
|
21209
21668
|
var CLAUDE_MODEL_CATALOG = {
|
|
21210
21669
|
updateMode: "unsupported",
|
|
@@ -21226,6 +21685,9 @@ class ClaudeDriver {
|
|
|
21226
21685
|
turnProtocol = new ClaudeTurnProtocol;
|
|
21227
21686
|
eventNormalizer = new ClaudeEventNormalizer(this.turnProtocol);
|
|
21228
21687
|
pendingInterrupt;
|
|
21688
|
+
discoverRecentContext(request) {
|
|
21689
|
+
return discoverClaudeRecentContext(request);
|
|
21690
|
+
}
|
|
21229
21691
|
beginTurn() {
|
|
21230
21692
|
this.pendingInterrupt = undefined;
|
|
21231
21693
|
const receipt = this.turnProtocol.beginTurn();
|
|
@@ -21489,16 +21951,16 @@ function normalizeFileChangeInput(item) {
|
|
|
21489
21951
|
for (const candidate of changePaths) {
|
|
21490
21952
|
if (typeof candidate !== "string")
|
|
21491
21953
|
continue;
|
|
21492
|
-
const
|
|
21493
|
-
if (!
|
|
21954
|
+
const path8 = candidate.trim();
|
|
21955
|
+
if (!path8 || seen.has(path8))
|
|
21494
21956
|
continue;
|
|
21495
|
-
seen.add(
|
|
21496
|
-
paths.push(
|
|
21957
|
+
seen.add(path8);
|
|
21958
|
+
paths.push(path8);
|
|
21497
21959
|
}
|
|
21498
21960
|
if (paths.length === 0 && typeof item?.path === "string") {
|
|
21499
|
-
const
|
|
21500
|
-
if (
|
|
21501
|
-
paths.push(
|
|
21961
|
+
const path8 = item.path.trim();
|
|
21962
|
+
if (path8)
|
|
21963
|
+
paths.push(path8);
|
|
21502
21964
|
}
|
|
21503
21965
|
return paths.length > 0 ? { path: paths.join(", ") } : {};
|
|
21504
21966
|
}
|
|
@@ -21867,7 +22329,7 @@ class CodexEventNormalizer {
|
|
|
21867
22329
|
|
|
21868
22330
|
// agent-driver/dist/adapters/codex/home.js
|
|
21869
22331
|
import * as os from "os";
|
|
21870
|
-
import * as
|
|
22332
|
+
import * as path8 from "path";
|
|
21871
22333
|
function readConfiguredCodexHome(env) {
|
|
21872
22334
|
const raw = env.CODEX_HOME;
|
|
21873
22335
|
return typeof raw === "string" && raw.trim().length > 0 ? raw : null;
|
|
@@ -21875,8 +22337,8 @@ function readConfiguredCodexHome(env) {
|
|
|
21875
22337
|
function resolveCodexHomeRootFromEnv(env = process.env, opts = {}) {
|
|
21876
22338
|
const raw = readConfiguredCodexHome(env);
|
|
21877
22339
|
if (raw)
|
|
21878
|
-
return
|
|
21879
|
-
return
|
|
22340
|
+
return path8.resolve(opts.cwd ?? process.cwd(), raw);
|
|
22341
|
+
return path8.join(opts.defaultHomeDir ?? os.homedir(), ".codex");
|
|
21880
22342
|
}
|
|
21881
22343
|
|
|
21882
22344
|
// agent-driver/dist/internal/errors.js
|
|
@@ -21969,6 +22431,49 @@ function parsePiModelCatalog(values) {
|
|
|
21969
22431
|
return catalogFromIds(ids);
|
|
21970
22432
|
}
|
|
21971
22433
|
|
|
22434
|
+
// agent-driver/dist/adapters/codex/recent-context.js
|
|
22435
|
+
import path9 from "node:path";
|
|
22436
|
+
function isChildSession(payload) {
|
|
22437
|
+
if (payload.parentThreadId != null || payload.parent_thread_id != null)
|
|
22438
|
+
return true;
|
|
22439
|
+
const source = payload.source;
|
|
22440
|
+
if (typeof source === "string")
|
|
22441
|
+
return source.toLowerCase().startsWith("subagent");
|
|
22442
|
+
const sourceRecord = asRecord(source);
|
|
22443
|
+
return sourceRecord != null && (("subagent" in sourceRecord) || ("subAgent" in sourceRecord));
|
|
22444
|
+
}
|
|
22445
|
+
async function discoverCodexRecentContext(request, dependencies = {}) {
|
|
22446
|
+
const collector = new RecentContextCollector(request, "supported");
|
|
22447
|
+
if (collector.satisfied)
|
|
22448
|
+
return collector.result();
|
|
22449
|
+
const sessionsRoot = path9.resolve(dependencies.sessionsRoot ?? path9.join(resolveCodexHomeRootFromEnv(), "sessions"));
|
|
22450
|
+
const readHeader = dependencies.readHeader ?? readFirstLine;
|
|
22451
|
+
const candidates = await collectJsonlFileCandidates(sessionsRoot, {
|
|
22452
|
+
readDirectory: dependencies.readDirectory,
|
|
22453
|
+
statPath: dependencies.statPath
|
|
22454
|
+
});
|
|
22455
|
+
candidates.sort((left, right) => right.modifiedAt.getTime() - left.modifiedAt.getTime());
|
|
22456
|
+
for (const candidate of candidates) {
|
|
22457
|
+
const line = await readHeader(candidate.filePath);
|
|
22458
|
+
if (!line)
|
|
22459
|
+
continue;
|
|
22460
|
+
const header = tryParseJsonRecord(line);
|
|
22461
|
+
if (!header)
|
|
22462
|
+
continue;
|
|
22463
|
+
const payload = asRecord(header.payload);
|
|
22464
|
+
if (header.type !== "session_meta" || !payload || isChildSession(payload))
|
|
22465
|
+
continue;
|
|
22466
|
+
collector.add({
|
|
22467
|
+
sessionFilePath: candidate.filePath,
|
|
22468
|
+
projectPath: payload.cwd,
|
|
22469
|
+
modifiedAt: candidate.modifiedAt
|
|
22470
|
+
});
|
|
22471
|
+
if (collector.satisfied)
|
|
22472
|
+
break;
|
|
22473
|
+
}
|
|
22474
|
+
return collector.result();
|
|
22475
|
+
}
|
|
22476
|
+
|
|
21972
22477
|
// agent-driver/dist/adapters/codex/index.js
|
|
21973
22478
|
var SETTINGS_UPDATE_TIMEOUT_MS = 5000;
|
|
21974
22479
|
var MODEL_LIST_TIMEOUT_MS = 5000;
|
|
@@ -21997,6 +22502,9 @@ class CodexDriver {
|
|
|
21997
22502
|
eventNormalizer = new CodexEventNormalizer;
|
|
21998
22503
|
pendingAccountReadRequestIds = new Set;
|
|
21999
22504
|
requestId = 0;
|
|
22505
|
+
discoverRecentContext(request) {
|
|
22506
|
+
return discoverCodexRecentContext(request);
|
|
22507
|
+
}
|
|
22000
22508
|
codexHomeRoot = null;
|
|
22001
22509
|
proc = null;
|
|
22002
22510
|
pendingInitialPrompt = null;
|
|
@@ -23173,6 +23681,196 @@ class CursorAcpLane {
|
|
|
23173
23681
|
}
|
|
23174
23682
|
}
|
|
23175
23683
|
|
|
23684
|
+
// agent-driver/dist/internal/discovery-process.js
|
|
23685
|
+
import { StringDecoder } from "node:string_decoder";
|
|
23686
|
+
function toBuffer(chunk2) {
|
|
23687
|
+
if (Buffer.isBuffer(chunk2))
|
|
23688
|
+
return chunk2;
|
|
23689
|
+
if (chunk2 instanceof Uint8Array)
|
|
23690
|
+
return Buffer.from(chunk2.buffer, chunk2.byteOffset, chunk2.byteLength);
|
|
23691
|
+
return Buffer.from(String(chunk2));
|
|
23692
|
+
}
|
|
23693
|
+
async function cleanupProcess(process3, label) {
|
|
23694
|
+
if (process3.pid)
|
|
23695
|
+
await killProcessTree(process3.pid, { graceMs: 250 });
|
|
23696
|
+
else if (process3.exitCode === null && process3.signalCode === null && !process3.kill("SIGTERM")) {
|
|
23697
|
+
throw new Error(`${label} discovery cleanup failed`);
|
|
23698
|
+
}
|
|
23699
|
+
}
|
|
23700
|
+
function onStream(stream, event, listener) {
|
|
23701
|
+
stream?.on?.(event, listener);
|
|
23702
|
+
}
|
|
23703
|
+
function runBoundedDiscoveryProcess(options) {
|
|
23704
|
+
return new Promise((resolve2, reject) => {
|
|
23705
|
+
const decoder = new StringDecoder("utf8");
|
|
23706
|
+
let settled = false;
|
|
23707
|
+
let decoderEnded = false;
|
|
23708
|
+
let outputBytes = 0;
|
|
23709
|
+
const settle = (result, error51) => {
|
|
23710
|
+
if (settled)
|
|
23711
|
+
return;
|
|
23712
|
+
settled = true;
|
|
23713
|
+
clearTimeout(timer);
|
|
23714
|
+
if (!decoderEnded)
|
|
23715
|
+
decoder.end();
|
|
23716
|
+
Promise.resolve().then(() => options.cleanup?.(options.process) ?? cleanupProcess(options.process, options.label)).then(() => error51 ? reject(error51) : resolve2(result), () => reject(error51 ?? new Error(`${options.label} discovery cleanup failed`)));
|
|
23717
|
+
};
|
|
23718
|
+
const control = {
|
|
23719
|
+
get outputBytes() {
|
|
23720
|
+
return outputBytes;
|
|
23721
|
+
},
|
|
23722
|
+
finish: (result) => settle(result),
|
|
23723
|
+
fail: (message2) => settle(undefined, new Error(message2)),
|
|
23724
|
+
flushStdout: () => {
|
|
23725
|
+
if (settled || decoderEnded)
|
|
23726
|
+
return;
|
|
23727
|
+
decoderEnded = true;
|
|
23728
|
+
options.onStdout(decoder.end(), true, control);
|
|
23729
|
+
},
|
|
23730
|
+
write: (line) => {
|
|
23731
|
+
const stdin = options.process.stdin;
|
|
23732
|
+
if (!stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false) {
|
|
23733
|
+
return control.fail(`${options.label} discovery transport is unavailable`);
|
|
23734
|
+
}
|
|
23735
|
+
try {
|
|
23736
|
+
stdin.write(line);
|
|
23737
|
+
} catch {
|
|
23738
|
+
control.fail(`${options.label} discovery transport write failed`);
|
|
23739
|
+
}
|
|
23740
|
+
}
|
|
23741
|
+
};
|
|
23742
|
+
const addBytes = (chunk2, decode3) => {
|
|
23743
|
+
if (settled)
|
|
23744
|
+
return;
|
|
23745
|
+
const bytes = toBuffer(chunk2);
|
|
23746
|
+
outputBytes += bytes.byteLength;
|
|
23747
|
+
if (outputBytes > options.outputMaxBytes) {
|
|
23748
|
+
control.fail(`${options.label} discovery output exceeded its bound`);
|
|
23749
|
+
} else if (decode3)
|
|
23750
|
+
options.onStdout(decoder.write(bytes), false, control);
|
|
23751
|
+
};
|
|
23752
|
+
const timer = setTimeout(() => control.fail(`${options.label} discovery timed out`), Math.max(1, options.timeoutMs));
|
|
23753
|
+
timer.unref?.();
|
|
23754
|
+
options.process.stdout?.on("data", (chunk2) => addBytes(chunk2, true));
|
|
23755
|
+
options.process.stderr?.on("data", (chunk2) => addBytes(chunk2, false));
|
|
23756
|
+
onStream(options.process.stdout, "end", control.flushStdout);
|
|
23757
|
+
for (const stream of [options.process.stdin, options.process.stdout, options.process.stderr]) {
|
|
23758
|
+
onStream(stream, "error", () => control.fail(`${options.label} discovery transport failed`));
|
|
23759
|
+
}
|
|
23760
|
+
options.process.on("error", () => control.fail(`${options.label} discovery process failed`));
|
|
23761
|
+
options.process.on(options.exitEvent, (code, signal) => options.onExit(code, signal, control));
|
|
23762
|
+
options.onStart?.(control);
|
|
23763
|
+
});
|
|
23764
|
+
}
|
|
23765
|
+
|
|
23766
|
+
// agent-driver/dist/adapters/cursor/recent-context.js
|
|
23767
|
+
var ACP_PROTOCOL_VERSION3 = 1;
|
|
23768
|
+
var AUTH_METHOD_ID3 = "cursor_login";
|
|
23769
|
+
var CURSOR_DISCOVERY_TIMEOUT_MS = 30000;
|
|
23770
|
+
var CURSOR_DISCOVERY_OUTPUT_MAX_BYTES = 4 * 1024 * 1024;
|
|
23771
|
+
async function discoverCursorRecentContext(request, dependencies = {}) {
|
|
23772
|
+
const collector = new RecentContextCollector(request, "unavailable");
|
|
23773
|
+
if (collector.satisfied)
|
|
23774
|
+
return collector.result();
|
|
23775
|
+
const spec = resolveSpawnSpec("cursor-agent", ["acp"], request.command);
|
|
23776
|
+
const processHandle = (dependencies.spawn ?? spawnAgentProcess)(spec.command, spec.args, {
|
|
23777
|
+
cwd: dependencies.cwd ?? process.cwd(),
|
|
23778
|
+
env: { ...process.env, CI: "1" },
|
|
23779
|
+
shell: spec.shell
|
|
23780
|
+
});
|
|
23781
|
+
let buffer = "";
|
|
23782
|
+
let requestId = 0;
|
|
23783
|
+
let expectedId = 0;
|
|
23784
|
+
let expectedMethod = "";
|
|
23785
|
+
const seenCursors = new Set;
|
|
23786
|
+
const requestRpc = (method, params, control) => {
|
|
23787
|
+
expectedId = ++requestId;
|
|
23788
|
+
expectedMethod = method;
|
|
23789
|
+
control.write(`${jsonRpcRequest(method, params, expectedId)}
|
|
23790
|
+
`);
|
|
23791
|
+
};
|
|
23792
|
+
const requestPage = (control, cursor) => requestRpc("session/list", cursor ? { cursor } : {}, control);
|
|
23793
|
+
const onLine = (line, control) => {
|
|
23794
|
+
const message2 = asRecord(tryParseJsonLine(line));
|
|
23795
|
+
if (!message2 || message2.id !== expectedId)
|
|
23796
|
+
return;
|
|
23797
|
+
if (message2.error !== undefined)
|
|
23798
|
+
return control.fail("Cursor discovery request failed");
|
|
23799
|
+
const result = asRecord(message2.result);
|
|
23800
|
+
if (!result)
|
|
23801
|
+
return control.fail("Cursor discovery returned an invalid response");
|
|
23802
|
+
if (expectedMethod === "initialize") {
|
|
23803
|
+
if (result.protocolVersion !== ACP_PROTOCOL_VERSION3) {
|
|
23804
|
+
return control.fail("Cursor discovery protocol is incompatible");
|
|
23805
|
+
}
|
|
23806
|
+
const capabilities = asRecord(result.agentCapabilities);
|
|
23807
|
+
const sessionCapabilities = asRecord(capabilities?.sessionCapabilities);
|
|
23808
|
+
if (sessionCapabilities?.list !== true && !asRecord(sessionCapabilities?.list)) {
|
|
23809
|
+
return control.fail("Cursor session listing is unavailable");
|
|
23810
|
+
}
|
|
23811
|
+
const authMethods = Array.isArray(result.authMethods) ? result.authMethods : [];
|
|
23812
|
+
if (!authMethods.some((method) => asRecord(method)?.id === AUTH_METHOD_ID3)) {
|
|
23813
|
+
return control.fail("Cursor discovery authentication is unavailable");
|
|
23814
|
+
}
|
|
23815
|
+
requestRpc("authenticate", { methodId: AUTH_METHOD_ID3 }, control);
|
|
23816
|
+
return;
|
|
23817
|
+
}
|
|
23818
|
+
if (expectedMethod === "authenticate") {
|
|
23819
|
+
requestPage(control);
|
|
23820
|
+
return;
|
|
23821
|
+
}
|
|
23822
|
+
if (expectedMethod !== "session/list")
|
|
23823
|
+
return control.fail("Cursor discovery state is invalid");
|
|
23824
|
+
const sessions = Array.isArray(result.sessions) ? result.sessions : Array.isArray(result.data) ? result.data : [];
|
|
23825
|
+
for (const value of sessions) {
|
|
23826
|
+
const session2 = asRecord(value);
|
|
23827
|
+
if (!session2)
|
|
23828
|
+
continue;
|
|
23829
|
+
collector.add({ projectPath: session2.cwd, modifiedAt: session2.updatedAt });
|
|
23830
|
+
if (collector.satisfied)
|
|
23831
|
+
return control.finish(collector.result());
|
|
23832
|
+
}
|
|
23833
|
+
const nextCursor = typeof result.nextCursor === "string" && result.nextCursor ? result.nextCursor : undefined;
|
|
23834
|
+
if (!nextCursor)
|
|
23835
|
+
return control.finish(collector.result());
|
|
23836
|
+
if (seenCursors.has(nextCursor))
|
|
23837
|
+
return control.fail("Cursor discovery cursor repeated");
|
|
23838
|
+
seenCursors.add(nextCursor);
|
|
23839
|
+
requestPage(control, nextCursor);
|
|
23840
|
+
};
|
|
23841
|
+
return runBoundedDiscoveryProcess({
|
|
23842
|
+
process: processHandle,
|
|
23843
|
+
label: "Cursor",
|
|
23844
|
+
timeoutMs: dependencies.timeoutMs ?? CURSOR_DISCOVERY_TIMEOUT_MS,
|
|
23845
|
+
outputMaxBytes: dependencies.outputMaxBytes ?? CURSOR_DISCOVERY_OUTPUT_MAX_BYTES,
|
|
23846
|
+
cleanup: dependencies.cleanup,
|
|
23847
|
+
exitEvent: "exit",
|
|
23848
|
+
onStdout: (text2, final, control) => {
|
|
23849
|
+
buffer += text2;
|
|
23850
|
+
const lines = buffer.split(`
|
|
23851
|
+
`);
|
|
23852
|
+
buffer = lines.pop() ?? "";
|
|
23853
|
+
for (const line of lines)
|
|
23854
|
+
if (line.trim())
|
|
23855
|
+
onLine(line, control);
|
|
23856
|
+
if (final && buffer.trim()) {
|
|
23857
|
+
const line = buffer;
|
|
23858
|
+
buffer = "";
|
|
23859
|
+
onLine(line, control);
|
|
23860
|
+
}
|
|
23861
|
+
},
|
|
23862
|
+
onExit: (_code, _signal, control) => control.fail("Cursor discovery process exited early"),
|
|
23863
|
+
onStart: (control) => requestRpc("initialize", {
|
|
23864
|
+
protocolVersion: ACP_PROTOCOL_VERSION3,
|
|
23865
|
+
clientCapabilities: {
|
|
23866
|
+
fs: { readTextFile: false, writeTextFile: false },
|
|
23867
|
+
terminal: false
|
|
23868
|
+
},
|
|
23869
|
+
clientInfo: { name: "alook-agent-driver-discovery", version: "0.1.31" }
|
|
23870
|
+
}, control)
|
|
23871
|
+
});
|
|
23872
|
+
}
|
|
23873
|
+
|
|
23176
23874
|
// agent-driver/dist/adapters/cursor/index.js
|
|
23177
23875
|
class CursorDriver {
|
|
23178
23876
|
catalogProbe;
|
|
@@ -23184,6 +23882,9 @@ class CursorDriver {
|
|
|
23184
23882
|
wakeStart: "immediate",
|
|
23185
23883
|
terminalOwnership: "transport_request"
|
|
23186
23884
|
};
|
|
23885
|
+
discoverRecentContext(request) {
|
|
23886
|
+
return discoverCursorRecentContext(request);
|
|
23887
|
+
}
|
|
23187
23888
|
constructor(catalogProbe = probeCursorAcpCatalog) {
|
|
23188
23889
|
this.catalogProbe = catalogProbe;
|
|
23189
23890
|
}
|
|
@@ -23678,7 +24379,7 @@ class OpenCodeServiceLane {
|
|
|
23678
24379
|
"/api/session/{sessionID}/permission/{requestID}/reply",
|
|
23679
24380
|
"/api/event"
|
|
23680
24381
|
];
|
|
23681
|
-
if (!paths || required2.some((
|
|
24382
|
+
if (!paths || required2.some((path10) => !record4(paths[path10]))) {
|
|
23682
24383
|
throw new OpenCodeIncompatibleError("Installed OpenCode service is missing required v2 session capabilities");
|
|
23683
24384
|
}
|
|
23684
24385
|
}
|
|
@@ -23736,8 +24437,8 @@ class OpenCodeServiceLane {
|
|
|
23736
24437
|
const controller = new AbortController;
|
|
23737
24438
|
this.durableAbort = controller;
|
|
23738
24439
|
try {
|
|
23739
|
-
const
|
|
23740
|
-
const response = await this.openStream(
|
|
24440
|
+
const path10 = `/api/session/${encodeURIComponent(this.sessionId)}/event?after=${this.lastDurableSeq}`;
|
|
24441
|
+
const response = await this.openStream(path10, controller, "durable event stream");
|
|
23741
24442
|
await this.catchUpHistory(true);
|
|
23742
24443
|
if (!this.isIdentity(identity))
|
|
23743
24444
|
return;
|
|
@@ -23811,12 +24512,12 @@ class OpenCodeServiceLane {
|
|
|
23811
24512
|
return;
|
|
23812
24513
|
this.protocolFailure(`OpenCode ${kind} stream stopped unexpectedly`, error51);
|
|
23813
24514
|
}
|
|
23814
|
-
async openStream(
|
|
24515
|
+
async openStream(path10, lifecycle, operation) {
|
|
23815
24516
|
const deadline = new AbortController;
|
|
23816
24517
|
const timeout = setTimeout(() => deadline.abort(), this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS);
|
|
23817
24518
|
timeout.unref?.();
|
|
23818
24519
|
try {
|
|
23819
|
-
const response = await this.fetchFn(`${this.baseUrl}${
|
|
24520
|
+
const response = await this.fetchFn(`${this.baseUrl}${path10}`, {
|
|
23820
24521
|
method: "GET",
|
|
23821
24522
|
headers: this.headers({ accept: "text/event-stream" }),
|
|
23822
24523
|
signal: AbortSignal.any([lifecycle.signal, deadline.signal])
|
|
@@ -24243,8 +24944,8 @@ class OpenCodeServiceLane {
|
|
|
24243
24944
|
turnOwner: root.receipt
|
|
24244
24945
|
});
|
|
24245
24946
|
}
|
|
24246
|
-
async requestNoContent(
|
|
24247
|
-
const response = await this.fetchWithTimeout(
|
|
24947
|
+
async requestNoContent(path10, method, body, operation) {
|
|
24948
|
+
const response = await this.fetchWithTimeout(path10, {
|
|
24248
24949
|
method,
|
|
24249
24950
|
...body ? {
|
|
24250
24951
|
headers: { "content-type": "application/json" },
|
|
@@ -24254,7 +24955,7 @@ class OpenCodeServiceLane {
|
|
|
24254
24955
|
if (!response.ok)
|
|
24255
24956
|
throw new OpenCodeHttpError(response.status, operation);
|
|
24256
24957
|
}
|
|
24257
|
-
async fetchWithTimeout(
|
|
24958
|
+
async fetchWithTimeout(path10, init, operation, timeoutMs = this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS) {
|
|
24258
24959
|
if (this.stopping)
|
|
24259
24960
|
throw new Error("OpenCode service lane is stopping");
|
|
24260
24961
|
const controller = new AbortController;
|
|
@@ -24262,7 +24963,7 @@ class OpenCodeServiceLane {
|
|
|
24262
24963
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
24263
24964
|
timer.unref?.();
|
|
24264
24965
|
try {
|
|
24265
|
-
return await this.fetchFn(`${this.baseUrl}${
|
|
24966
|
+
return await this.fetchFn(`${this.baseUrl}${path10}`, {
|
|
24266
24967
|
...init,
|
|
24267
24968
|
headers: this.headers(init.headers),
|
|
24268
24969
|
signal: controller.signal
|
|
@@ -24274,7 +24975,7 @@ class OpenCodeServiceLane {
|
|
|
24274
24975
|
this.requestControllers.delete(controller);
|
|
24275
24976
|
}
|
|
24276
24977
|
}
|
|
24277
|
-
async fetchJsonWithTimeout(
|
|
24978
|
+
async fetchJsonWithTimeout(path10, init, operation, timeoutMs = this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS) {
|
|
24278
24979
|
if (this.stopping)
|
|
24279
24980
|
throw new OpenCodeStoppedError("OpenCode service lane is stopping");
|
|
24280
24981
|
const controller = new AbortController;
|
|
@@ -24286,7 +24987,7 @@ class OpenCodeServiceLane {
|
|
|
24286
24987
|
}, timeoutMs);
|
|
24287
24988
|
timer.unref?.();
|
|
24288
24989
|
try {
|
|
24289
|
-
const response = await this.fetchFn(`${this.baseUrl}${
|
|
24990
|
+
const response = await this.fetchFn(`${this.baseUrl}${path10}`, {
|
|
24290
24991
|
...init,
|
|
24291
24992
|
headers: this.headers(init.headers),
|
|
24292
24993
|
signal: controller.signal
|
|
@@ -24379,6 +25080,75 @@ class OpenCodeServiceLane {
|
|
|
24379
25080
|
}
|
|
24380
25081
|
}
|
|
24381
25082
|
|
|
25083
|
+
// agent-driver/dist/adapters/opencode/recent-context.js
|
|
25084
|
+
var OPENCODE_DISCOVERY_TIMEOUT_MS = 15000;
|
|
25085
|
+
var OPENCODE_DISCOVERY_OUTPUT_MAX_BYTES = 4 * 1024 * 1024;
|
|
25086
|
+
function collectCommandOutput(command, args, shell, dependencies, timeoutMs, outputMaxBytes) {
|
|
25087
|
+
const processHandle = (dependencies.spawn ?? spawnAgentProcess)(command, args, {
|
|
25088
|
+
cwd: dependencies.cwd ?? process.cwd(),
|
|
25089
|
+
env: { ...process.env, CI: "1" },
|
|
25090
|
+
shell,
|
|
25091
|
+
stdin: "ignore"
|
|
25092
|
+
});
|
|
25093
|
+
let output = "";
|
|
25094
|
+
return runBoundedDiscoveryProcess({
|
|
25095
|
+
process: processHandle,
|
|
25096
|
+
label: "OpenCode",
|
|
25097
|
+
timeoutMs,
|
|
25098
|
+
outputMaxBytes,
|
|
25099
|
+
cleanup: dependencies.cleanup,
|
|
25100
|
+
exitEvent: "close",
|
|
25101
|
+
onStdout: (text2) => {
|
|
25102
|
+
output += text2;
|
|
25103
|
+
},
|
|
25104
|
+
onExit: (code, _signal, control) => {
|
|
25105
|
+
if (code !== 0)
|
|
25106
|
+
return control.fail("OpenCode session listing failed");
|
|
25107
|
+
control.flushStdout();
|
|
25108
|
+
control.finish({ output, outputBytes: control.outputBytes });
|
|
25109
|
+
}
|
|
25110
|
+
});
|
|
25111
|
+
}
|
|
25112
|
+
async function discoverOpenCodeRecentContext(request, dependencies = {}) {
|
|
25113
|
+
const collector = new RecentContextCollector(request, "unavailable");
|
|
25114
|
+
if (collector.satisfied)
|
|
25115
|
+
return collector.result();
|
|
25116
|
+
const startedAt = Date.now();
|
|
25117
|
+
const timeoutMs = dependencies.timeoutMs ?? OPENCODE_DISCOVERY_TIMEOUT_MS;
|
|
25118
|
+
let remainingOutputBytes = dependencies.outputMaxBytes ?? OPENCODE_DISCOVERY_OUTPUT_MAX_BYTES;
|
|
25119
|
+
let maxCount = Math.max(1, Math.min(Number.MAX_SAFE_INTEGER, request.recentProjectsTopK * 10));
|
|
25120
|
+
while (!collector.satisfied) {
|
|
25121
|
+
const remainingTimeoutMs = timeoutMs - (Date.now() - startedAt);
|
|
25122
|
+
if (remainingTimeoutMs <= 0)
|
|
25123
|
+
throw new Error("OpenCode discovery timed out");
|
|
25124
|
+
const spec = resolveSpawnSpec("opencode", ["session", "list", "--format", "json", "--max-count", String(maxCount), "--pure"], request.command);
|
|
25125
|
+
const commandOutput = await collectCommandOutput(spec.command, spec.args, spec.shell, dependencies, remainingTimeoutMs, remainingOutputBytes);
|
|
25126
|
+
remainingOutputBytes -= commandOutput.outputBytes;
|
|
25127
|
+
let parsed;
|
|
25128
|
+
try {
|
|
25129
|
+
parsed = JSON.parse(commandOutput.output);
|
|
25130
|
+
} catch {
|
|
25131
|
+
throw new Error("OpenCode session listing returned invalid JSON");
|
|
25132
|
+
}
|
|
25133
|
+
if (!Array.isArray(parsed))
|
|
25134
|
+
throw new Error("OpenCode session listing returned an invalid response");
|
|
25135
|
+
for (const value of parsed) {
|
|
25136
|
+
const session2 = asRecord(value);
|
|
25137
|
+
if (!session2)
|
|
25138
|
+
continue;
|
|
25139
|
+
const modifiedAt = session2.updated ?? session2.updatedAt;
|
|
25140
|
+
collector.add({ projectPath: session2.directory, modifiedAt });
|
|
25141
|
+
}
|
|
25142
|
+
if (collector.satisfied || parsed.length < maxCount)
|
|
25143
|
+
break;
|
|
25144
|
+
const nextMaxCount = Math.min(Number.MAX_SAFE_INTEGER, maxCount * 2);
|
|
25145
|
+
if (nextMaxCount === maxCount)
|
|
25146
|
+
throw new Error("OpenCode session listing could not prove the requested Top-K");
|
|
25147
|
+
maxCount = nextMaxCount;
|
|
25148
|
+
}
|
|
25149
|
+
return collector.result();
|
|
25150
|
+
}
|
|
25151
|
+
|
|
24382
25152
|
// agent-driver/dist/adapters/opencode/index.js
|
|
24383
25153
|
function createOpenCodeMessageId() {
|
|
24384
25154
|
return `msg_${randomBytes3(16).toString("hex")}`;
|
|
@@ -24397,6 +25167,9 @@ class OpenCodeDriver {
|
|
|
24397
25167
|
constructor(outputProbe = probeCommandOutput) {
|
|
24398
25168
|
this.outputProbe = outputProbe;
|
|
24399
25169
|
}
|
|
25170
|
+
discoverRecentContext(request) {
|
|
25171
|
+
return discoverOpenCodeRecentContext(request);
|
|
25172
|
+
}
|
|
24400
25173
|
probe(command) {
|
|
24401
25174
|
const result = probeCliRuntime("opencode", {}, command);
|
|
24402
25175
|
if (result.status !== "healthy")
|
|
@@ -24443,8 +25216,8 @@ class OpenCodeDriver {
|
|
|
24443
25216
|
// agent-driver/dist/adapters/pi/index.js
|
|
24444
25217
|
import { createRequire as createRequire2 } from "module";
|
|
24445
25218
|
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3, realpathSync } from "fs";
|
|
24446
|
-
import { homedir as
|
|
24447
|
-
import * as
|
|
25219
|
+
import { homedir as homedir4 } from "os";
|
|
25220
|
+
import * as path12 from "path";
|
|
24448
25221
|
|
|
24449
25222
|
// agent-driver/dist/controller/sdk-host.js
|
|
24450
25223
|
import { EventEmitter as EventEmitter4 } from "events";
|
|
@@ -24559,7 +25332,7 @@ class SdkLane {
|
|
|
24559
25332
|
|
|
24560
25333
|
// agent-driver/dist/adapters/pi/sessionDeps.js
|
|
24561
25334
|
import { readFileSync as readFileSync2 } from "fs";
|
|
24562
|
-
import * as
|
|
25335
|
+
import * as path10 from "path";
|
|
24563
25336
|
import { pathToFileURL } from "url";
|
|
24564
25337
|
var PI_SDK_PACKAGE_NAME = "@earendil-works/pi-coding-agent";
|
|
24565
25338
|
var cachedSdkPromise = null;
|
|
@@ -24568,9 +25341,9 @@ async function importPiSdkFromGlobalInstall() {
|
|
|
24568
25341
|
if (!dir) {
|
|
24569
25342
|
throw new Error(`${PI_SDK_PACKAGE_NAME} not found — install it (e.g. \`npm install -g ${PI_SDK_PACKAGE_NAME}\`) before launching a pi agent`);
|
|
24570
25343
|
}
|
|
24571
|
-
const pkg = JSON.parse(readFileSync2(
|
|
25344
|
+
const pkg = JSON.parse(readFileSync2(path10.join(dir, "package.json"), "utf-8"));
|
|
24572
25345
|
const entry = pkg.exports?.["."]?.import ?? pkg.main ?? "./dist/index.js";
|
|
24573
|
-
const entryPath =
|
|
25346
|
+
const entryPath = path10.join(dir, entry);
|
|
24574
25347
|
const barrel = await import(pathToFileURL(entryPath).href);
|
|
24575
25348
|
return withSessionDirHelper(barrel, entryPath);
|
|
24576
25349
|
}
|
|
@@ -24578,7 +25351,7 @@ async function withSessionDirHelper(barrel, entryPath) {
|
|
|
24578
25351
|
if (typeof barrel.getDefaultSessionDir === "function")
|
|
24579
25352
|
return barrel;
|
|
24580
25353
|
try {
|
|
24581
|
-
const deepPath =
|
|
25354
|
+
const deepPath = path10.join(path10.dirname(entryPath), "core", "session-manager.js");
|
|
24582
25355
|
const deep = await import(pathToFileURL(deepPath).href);
|
|
24583
25356
|
if (typeof deep.getDefaultSessionDir !== "function")
|
|
24584
25357
|
return barrel;
|
|
@@ -24658,6 +25431,51 @@ function createPiSessionDependencies(ctx, loadSdk = loadPiSdkModule) {
|
|
|
24658
25431
|
};
|
|
24659
25432
|
}
|
|
24660
25433
|
|
|
25434
|
+
// agent-driver/dist/adapters/pi/recent-context.js
|
|
25435
|
+
import { homedir as homedir3 } from "node:os";
|
|
25436
|
+
import path11 from "node:path";
|
|
25437
|
+
function expandTildePath(value) {
|
|
25438
|
+
if (value === "~")
|
|
25439
|
+
return homedir3();
|
|
25440
|
+
if (value.startsWith("~/"))
|
|
25441
|
+
return path11.join(homedir3(), value.slice(2));
|
|
25442
|
+
return value;
|
|
25443
|
+
}
|
|
25444
|
+
async function discoverPiRecentContext(request, dependencies = {}) {
|
|
25445
|
+
const collector = new RecentContextCollector(request, "supported");
|
|
25446
|
+
if (collector.satisfied)
|
|
25447
|
+
return collector.result();
|
|
25448
|
+
const customSessionDirectory = process.env.PI_CODING_AGENT_SESSION_DIR;
|
|
25449
|
+
const sessionsRoot = path11.resolve(expandTildePath(dependencies.sessionsRoot ?? customSessionDirectory ?? path11.join(process.env.PI_CODING_AGENT_DIR || path11.join(homedir3(), ".pi", "agent"), "sessions")));
|
|
25450
|
+
const scanDirectSessions = dependencies.sessionsRoot == null && customSessionDirectory != null;
|
|
25451
|
+
const readHeader = dependencies.readHeader ?? readFirstLine;
|
|
25452
|
+
const candidates = await collectJsonlFileCandidates(sessionsRoot, {
|
|
25453
|
+
includeRootFiles: scanDirectSessions,
|
|
25454
|
+
maxDepth: 1,
|
|
25455
|
+
readDirectory: dependencies.readDirectory,
|
|
25456
|
+
statPath: dependencies.statPath
|
|
25457
|
+
});
|
|
25458
|
+
candidates.sort((left, right) => right.modifiedAt.getTime() - left.modifiedAt.getTime());
|
|
25459
|
+
for (const candidate of candidates) {
|
|
25460
|
+
const line = await readHeader(candidate.filePath);
|
|
25461
|
+
if (!line)
|
|
25462
|
+
continue;
|
|
25463
|
+
const header = tryParseJsonRecord(line);
|
|
25464
|
+
if (!header)
|
|
25465
|
+
continue;
|
|
25466
|
+
if (header.type !== "session" || header.parentSession != null)
|
|
25467
|
+
continue;
|
|
25468
|
+
collector.add({
|
|
25469
|
+
sessionFilePath: candidate.filePath,
|
|
25470
|
+
projectPath: header.cwd,
|
|
25471
|
+
modifiedAt: candidate.modifiedAt
|
|
25472
|
+
});
|
|
25473
|
+
if (collector.satisfied)
|
|
25474
|
+
break;
|
|
25475
|
+
}
|
|
25476
|
+
return collector.result();
|
|
25477
|
+
}
|
|
25478
|
+
|
|
24661
25479
|
// agent-driver/dist/adapters/pi/index.js
|
|
24662
25480
|
var PI_SDK_PACKAGE_NAME2 = "@earendil-works/pi-coding-agent";
|
|
24663
25481
|
var PI_MODEL_PROBE_TIMEOUT_MS = 5000;
|
|
@@ -24676,15 +25494,15 @@ function resolvePiSdkPackageDir(deps = {}) {
|
|
|
24676
25494
|
if (!binPath)
|
|
24677
25495
|
return;
|
|
24678
25496
|
try {
|
|
24679
|
-
let dir =
|
|
25497
|
+
let dir = path12.dirname(realpathSync(binPath));
|
|
24680
25498
|
const MAX_DEPTH = 8;
|
|
24681
25499
|
for (let i = 0;i < MAX_DEPTH; i++) {
|
|
24682
|
-
if (isPiSdkPackageJson(
|
|
25500
|
+
if (isPiSdkPackageJson(path12.join(dir, "package.json")))
|
|
24683
25501
|
return dir;
|
|
24684
|
-
const siblingDir =
|
|
24685
|
-
if (isPiSdkPackageJson(
|
|
25502
|
+
const siblingDir = path12.join(dir, "node_modules", PI_SDK_PACKAGE_NAME2);
|
|
25503
|
+
if (isPiSdkPackageJson(path12.join(siblingDir, "package.json")))
|
|
24686
25504
|
return siblingDir;
|
|
24687
|
-
const parent =
|
|
25505
|
+
const parent = path12.dirname(dir);
|
|
24688
25506
|
if (parent === dir)
|
|
24689
25507
|
break;
|
|
24690
25508
|
dir = parent;
|
|
@@ -24701,21 +25519,21 @@ function findPiSessionFile(sessionDir, sessionId) {
|
|
|
24701
25519
|
}
|
|
24702
25520
|
const suffix = `_${sessionId}.jsonl`;
|
|
24703
25521
|
const match = entries.find((entry) => entry.endsWith(suffix));
|
|
24704
|
-
return match ?
|
|
25522
|
+
return match ? path12.join(sessionDir, match) : null;
|
|
24705
25523
|
}
|
|
24706
25524
|
function resolvePiSessionDir(sdk, cwd) {
|
|
24707
25525
|
if (typeof sdk.getDefaultSessionDir === "function")
|
|
24708
25526
|
return sdk.getDefaultSessionDir(cwd);
|
|
24709
|
-
const agentDir = typeof sdk.getAgentDir === "function" ? sdk.getAgentDir() :
|
|
24710
|
-
const encoded = `--${
|
|
24711
|
-
return
|
|
25527
|
+
const agentDir = typeof sdk.getAgentDir === "function" ? sdk.getAgentDir() : path12.join(homedir4(), ".pi", "agent");
|
|
25528
|
+
const encoded = `--${path12.resolve(cwd).replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
|
|
25529
|
+
return path12.join(agentDir, "sessions", encoded);
|
|
24712
25530
|
}
|
|
24713
25531
|
function resolvePiSdkVersionFromPath(deps = {}) {
|
|
24714
25532
|
const dir = resolvePiSdkPackageDir(deps);
|
|
24715
25533
|
if (!dir)
|
|
24716
25534
|
return;
|
|
24717
25535
|
try {
|
|
24718
|
-
const pkg = JSON.parse(readFileSync3(
|
|
25536
|
+
const pkg = JSON.parse(readFileSync3(path12.join(dir, "package.json"), "utf-8"));
|
|
24719
25537
|
return pkg.version;
|
|
24720
25538
|
} catch {
|
|
24721
25539
|
return;
|
|
@@ -24819,6 +25637,9 @@ class PiDriver {
|
|
|
24819
25637
|
};
|
|
24820
25638
|
sessionId = null;
|
|
24821
25639
|
terminalSequence = 0;
|
|
25640
|
+
discoverRecentContext(request) {
|
|
25641
|
+
return discoverPiRecentContext(request);
|
|
25642
|
+
}
|
|
24822
25643
|
constructor(dependenciesFor = createPiSessionDependencies, loadSdk = loadPiSdkModule, readVersion = readPiSdkVersion) {
|
|
24823
25644
|
this.dependenciesFor = dependenciesFor;
|
|
24824
25645
|
this.loadSdk = loadSdk;
|
|
@@ -24964,6 +25785,9 @@ function assertAdapterCompatibility(registrationId, registeredCapabilities, adap
|
|
|
24964
25785
|
if (typeof candidate[method] !== "function")
|
|
24965
25786
|
throw new Error(`Adapter ${registrationId} is missing ${method}()`);
|
|
24966
25787
|
}
|
|
25788
|
+
if (candidate.discoverRecentContext !== undefined && typeof candidate.discoverRecentContext !== "function") {
|
|
25789
|
+
throw new Error(`Adapter ${registrationId} has an invalid discoverRecentContext()`);
|
|
25790
|
+
}
|
|
24967
25791
|
const instruction = candidate.instructionDelivery;
|
|
24968
25792
|
if (!instruction || instruction.kind !== "native" && instruction.kind !== "workspace_file") {
|
|
24969
25793
|
throw new Error(`Adapter ${registrationId} has an invalid instructionDelivery declaration`);
|
|
@@ -25185,8 +26009,8 @@ function ensureSymlinks(workDir, canonical = CANONICAL_FILE, aliases = SYMLINK_A
|
|
|
25185
26009
|
continue;
|
|
25186
26010
|
const aliasPath = join8(workDir, alias2);
|
|
25187
26011
|
try {
|
|
25188
|
-
const
|
|
25189
|
-
if (
|
|
26012
|
+
const stat2 = lstatSync(aliasPath);
|
|
26013
|
+
if (stat2.isSymbolicLink()) {
|
|
25190
26014
|
const target2 = readlinkSync(aliasPath);
|
|
25191
26015
|
if (target2 === canonical)
|
|
25192
26016
|
continue;
|
|
@@ -25349,6 +26173,7 @@ class LogicalAgentSession {
|
|
|
25349
26173
|
steeringDeliveries = new Set;
|
|
25350
26174
|
laneAdmissionTail = Promise.resolve();
|
|
25351
26175
|
laneAdmissionPending = 0;
|
|
26176
|
+
toolBoundaryOpen = true;
|
|
25352
26177
|
toolBoundaryFlushDisabled = false;
|
|
25353
26178
|
safeBoundaryFlush;
|
|
25354
26179
|
safeBoundaryDelivery;
|
|
@@ -25629,6 +26454,8 @@ class LogicalAgentSession {
|
|
|
25629
26454
|
this.turnError = undefined;
|
|
25630
26455
|
this.interruptedTurnId = undefined;
|
|
25631
26456
|
this.processTurnEnded = false;
|
|
26457
|
+
this.toolBoundaryOpen = true;
|
|
26458
|
+
this.toolBoundaryFlushDisabled = false;
|
|
25632
26459
|
this.state = "starting";
|
|
25633
26460
|
const generation = this.lifecycleGeneration;
|
|
25634
26461
|
const text2 = messages.map((message2) => message2.text).join(`
|
|
@@ -25861,6 +26688,7 @@ class LogicalAgentSession {
|
|
|
25861
26688
|
}
|
|
25862
26689
|
if (!this.startToolUse(event.callId))
|
|
25863
26690
|
return;
|
|
26691
|
+
this.toolBoundaryOpen = false;
|
|
25864
26692
|
const startedCallId = this.toolCallId(event.callId);
|
|
25865
26693
|
this.emit({
|
|
25866
26694
|
type: "tool_started",
|
|
@@ -25877,6 +26705,7 @@ class LogicalAgentSession {
|
|
|
25877
26705
|
}
|
|
25878
26706
|
if (!this.finishToolUse(event.callId))
|
|
25879
26707
|
return;
|
|
26708
|
+
this.toolBoundaryOpen = true;
|
|
25880
26709
|
const finishedCallId = this.toolCallId(event.callId);
|
|
25881
26710
|
this.emit({
|
|
25882
26711
|
type: "tool_finished",
|
|
@@ -25884,7 +26713,7 @@ class LogicalAgentSession {
|
|
|
25884
26713
|
...finishedCallId ? { callId: finishedCallId } : {},
|
|
25885
26714
|
name: event.name
|
|
25886
26715
|
});
|
|
25887
|
-
if (
|
|
26716
|
+
if (!this.toolBoundaryFlushDisabled)
|
|
25888
26717
|
this.flushSafeBoundaryQueue();
|
|
25889
26718
|
return;
|
|
25890
26719
|
case "compaction_started":
|
|
@@ -26030,6 +26859,7 @@ class LogicalAgentSession {
|
|
|
26030
26859
|
this.clearOutstandingToolUses();
|
|
26031
26860
|
this.compacting = false;
|
|
26032
26861
|
this.reviewing = false;
|
|
26862
|
+
this.toolBoundaryOpen = true;
|
|
26033
26863
|
this.toolBoundaryFlushDisabled = false;
|
|
26034
26864
|
this.state = "idle";
|
|
26035
26865
|
if (this.adapter.execution.lifetime === "turn") {
|
|
@@ -26051,7 +26881,7 @@ class LogicalAgentSession {
|
|
|
26051
26881
|
return this.safeBoundaryFlush;
|
|
26052
26882
|
}
|
|
26053
26883
|
canFlushSafeBoundaryQueue() {
|
|
26054
|
-
return this.state === "working" && this.behavior.midTurnDelivery === "safe_boundary_queue" && this.
|
|
26884
|
+
return this.state === "working" && this.behavior.midTurnDelivery === "safe_boundary_queue" && this.toolBoundaryOpen && !this.toolBoundaryFlushDisabled && !this.compacting && !this.reviewing && this.activeTurn !== undefined && this.lane !== null && this.queued.length > 0;
|
|
26055
26885
|
}
|
|
26056
26886
|
async drainSafeBoundaryQueue() {
|
|
26057
26887
|
while (this.canFlushSafeBoundaryQueue()) {
|
|
@@ -26566,6 +27396,57 @@ function createAgentDriverSdkWithRegistry(options) {
|
|
|
26566
27396
|
const registry2 = options.registry;
|
|
26567
27397
|
return {
|
|
26568
27398
|
backendIds: registry2.backendIds,
|
|
27399
|
+
async discoverRecentContext(input) {
|
|
27400
|
+
if (!isValidRecentContextTopK(input.recentSessionFilesTopK) || !isValidRecentContextTopK(input.recentProjectsTopK)) {
|
|
27401
|
+
return {
|
|
27402
|
+
ok: false,
|
|
27403
|
+
error: {
|
|
27404
|
+
category: "configuration",
|
|
27405
|
+
code: "invalid_recent_context_top_k",
|
|
27406
|
+
message: "Recent-context Top-K values must be non-negative safe integers",
|
|
27407
|
+
retryable: false
|
|
27408
|
+
}
|
|
27409
|
+
};
|
|
27410
|
+
}
|
|
27411
|
+
const registration = registry2.get(input.backend);
|
|
27412
|
+
try {
|
|
27413
|
+
assertRegistrationShape(registration);
|
|
27414
|
+
const adapter = registration.createAdapter();
|
|
27415
|
+
assertAdapterCompatibility(String(registration.id), registration.capabilities, adapter);
|
|
27416
|
+
if (!adapter.discoverRecentContext) {
|
|
27417
|
+
return {
|
|
27418
|
+
ok: false,
|
|
27419
|
+
error: {
|
|
27420
|
+
category: "configuration",
|
|
27421
|
+
code: "recent_context_discovery_unsupported",
|
|
27422
|
+
message: `Backend ${input.backend} does not support recent-context discovery`,
|
|
27423
|
+
retryable: false
|
|
27424
|
+
}
|
|
27425
|
+
};
|
|
27426
|
+
}
|
|
27427
|
+
const command = registration.capabilities.commandOverride ? input.command : undefined;
|
|
27428
|
+
const discovered = await adapter.discoverRecentContext({
|
|
27429
|
+
recentSessionFilesTopK: input.recentSessionFilesTopK,
|
|
27430
|
+
recentProjectsTopK: input.recentProjectsTopK,
|
|
27431
|
+
...command ? { command } : {}
|
|
27432
|
+
});
|
|
27433
|
+
const sanitized = sanitizeRecentContextData(discovered, input);
|
|
27434
|
+
if (!sanitized)
|
|
27435
|
+
throw new Error(`Adapter ${input.backend} returned invalid recent-context data`);
|
|
27436
|
+
return { ok: true, ...sanitized };
|
|
27437
|
+
} catch (error51) {
|
|
27438
|
+
const contractInvalid = error51 instanceof Error && (error51.message.startsWith("Adapter ") || error51.message.startsWith("Agent backend registration "));
|
|
27439
|
+
return {
|
|
27440
|
+
ok: false,
|
|
27441
|
+
error: {
|
|
27442
|
+
category: contractInvalid ? "internal" : "runtime_unavailable",
|
|
27443
|
+
code: contractInvalid ? "adapter_contract_invalid" : "recent_context_discovery_failed",
|
|
27444
|
+
message: contractInvalid ? `Backend ${input.backend} adapter contract is invalid` : `Backend ${input.backend} recent-context discovery failed`,
|
|
27445
|
+
retryable: !contractInvalid
|
|
27446
|
+
}
|
|
27447
|
+
};
|
|
27448
|
+
}
|
|
27449
|
+
},
|
|
26569
27450
|
async probe(input) {
|
|
26570
27451
|
const registration = registry2.get(input.backend);
|
|
26571
27452
|
const capabilities2 = registration.capabilities;
|
|
@@ -26704,22 +27585,22 @@ function listRuntimeIds() {
|
|
|
26704
27585
|
|
|
26705
27586
|
// src/discovery.ts
|
|
26706
27587
|
function resolveAlookCliPath(moduleDir) {
|
|
26707
|
-
const thisDir = moduleDir ??
|
|
26708
|
-
const target2 =
|
|
27588
|
+
const thisDir = moduleDir ?? path13.dirname(fileURLToPath(import.meta.url));
|
|
27589
|
+
const target2 = path13.basename(thisDir) === "dist" ? path13.resolve(thisDir, "cli", "index.js") : path13.resolve(thisDir, "..", "scripts", "alook-shim.mjs");
|
|
26709
27590
|
return fs6.existsSync(target2) ? target2 : null;
|
|
26710
27591
|
}
|
|
26711
27592
|
function deriveCliFallbackCandidates(cliPath) {
|
|
26712
27593
|
if (!cliPath)
|
|
26713
27594
|
return [];
|
|
26714
|
-
const normalized = cliPath.split(
|
|
27595
|
+
const normalized = cliPath.split(path13.sep).join("/");
|
|
26715
27596
|
const marker = "/node_modules/";
|
|
26716
27597
|
const idx = normalized.indexOf(marker);
|
|
26717
27598
|
if (idx === -1)
|
|
26718
27599
|
return [];
|
|
26719
27600
|
const globalRoot = cliPath.slice(0, idx + marker.length - 1);
|
|
26720
|
-
const tail =
|
|
27601
|
+
const tail = path13.join("dist", "cli", "index.js");
|
|
26721
27602
|
return [
|
|
26722
|
-
|
|
27603
|
+
path13.join(globalRoot, "@alook", "daemon", tail)
|
|
26723
27604
|
].filter((candidate) => candidate !== cliPath);
|
|
26724
27605
|
}
|
|
26725
27606
|
function resolveAlookCliPathWithFallback(primary) {
|
|
@@ -26861,11 +27742,11 @@ function readDaemonVersion() {
|
|
|
26861
27742
|
|
|
26862
27743
|
// src/cli/daemonRunner.ts
|
|
26863
27744
|
import * as fs11 from "node:fs";
|
|
26864
|
-
import * as
|
|
27745
|
+
import * as path16 from "node:path";
|
|
26865
27746
|
import { WebSocket } from "ws";
|
|
26866
27747
|
|
|
26867
27748
|
// src/daemon/createDaemon.ts
|
|
26868
|
-
import { homedir as
|
|
27749
|
+
import { homedir as homedir7 } from "os";
|
|
26869
27750
|
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync8 } from "node:fs";
|
|
26870
27751
|
|
|
26871
27752
|
// src/util/rotatingFileSink.ts
|
|
@@ -26882,7 +27763,7 @@ import {
|
|
|
26882
27763
|
statSync,
|
|
26883
27764
|
unlinkSync as unlinkSync3
|
|
26884
27765
|
} from "node:fs";
|
|
26885
|
-
function createRotatingFileSink(
|
|
27766
|
+
function createRotatingFileSink(path14, maxBytes, opts = {}) {
|
|
26886
27767
|
const report = (operation, error51) => {
|
|
26887
27768
|
try {
|
|
26888
27769
|
opts.onError?.({ operation, error: error51 });
|
|
@@ -26892,8 +27773,8 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
|
|
|
26892
27773
|
if (!existsSync6(filePath))
|
|
26893
27774
|
return true;
|
|
26894
27775
|
try {
|
|
26895
|
-
const
|
|
26896
|
-
if (!
|
|
27776
|
+
const stat2 = lstatSync2(filePath);
|
|
27777
|
+
if (!stat2.isFile()) {
|
|
26897
27778
|
if (opts.mode === undefined && !opts.hardMaxBytes)
|
|
26898
27779
|
return true;
|
|
26899
27780
|
report("unsafe_generation", new Error("log generation is not a regular file"));
|
|
@@ -26901,7 +27782,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
|
|
|
26901
27782
|
}
|
|
26902
27783
|
if (opts.mode !== undefined)
|
|
26903
27784
|
chmodSync(filePath, opts.mode);
|
|
26904
|
-
if (opts.hardMaxBytes && maxBytes > 0 &&
|
|
27785
|
+
if (opts.hardMaxBytes && maxBytes > 0 && stat2.size > maxBytes) {
|
|
26905
27786
|
try {
|
|
26906
27787
|
unlinkSync3(filePath);
|
|
26907
27788
|
} catch (error51) {
|
|
@@ -26918,9 +27799,9 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
|
|
|
26918
27799
|
};
|
|
26919
27800
|
const rotate = () => {
|
|
26920
27801
|
try {
|
|
26921
|
-
renameSync2(
|
|
27802
|
+
renameSync2(path14, `${path14}.1`);
|
|
26922
27803
|
if (opts.mode !== undefined)
|
|
26923
|
-
chmodSync(`${
|
|
27804
|
+
chmodSync(`${path14}.1`, opts.mode);
|
|
26924
27805
|
return true;
|
|
26925
27806
|
} catch (error51) {
|
|
26926
27807
|
report("rotate", error51);
|
|
@@ -26929,7 +27810,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
|
|
|
26929
27810
|
};
|
|
26930
27811
|
const currentSize = () => {
|
|
26931
27812
|
try {
|
|
26932
|
-
return existsSync6(
|
|
27813
|
+
return existsSync6(path14) ? statSync(path14).size : 0;
|
|
26933
27814
|
} catch (error51) {
|
|
26934
27815
|
report("stat", error51);
|
|
26935
27816
|
return null;
|
|
@@ -26937,7 +27818,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
|
|
|
26937
27818
|
};
|
|
26938
27819
|
const sink = {
|
|
26939
27820
|
secure() {
|
|
26940
|
-
return secureGeneration(`${
|
|
27821
|
+
return secureGeneration(`${path14}.1`) && secureGeneration(path14);
|
|
26941
27822
|
},
|
|
26942
27823
|
write(line) {
|
|
26943
27824
|
try {
|
|
@@ -26957,7 +27838,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
|
|
|
26957
27838
|
const shouldRotate = maxBytes > 0 && (opts.hardMaxBytes ? currentBytes > 0 && currentBytes + serializedBytes > maxBytes : currentBytes >= maxBytes);
|
|
26958
27839
|
if (shouldRotate && !rotate() && opts.hardMaxBytes)
|
|
26959
27840
|
return;
|
|
26960
|
-
appendFileSync(
|
|
27841
|
+
appendFileSync(path14, serialized, opts.mode === undefined ? undefined : { mode: opts.mode });
|
|
26961
27842
|
} catch (error51) {
|
|
26962
27843
|
report("append", error51);
|
|
26963
27844
|
}
|
|
@@ -26965,7 +27846,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
|
|
|
26965
27846
|
openSnapshot() {
|
|
26966
27847
|
const files = [];
|
|
26967
27848
|
try {
|
|
26968
|
-
for (const candidate of [`${
|
|
27849
|
+
for (const candidate of [`${path14}.1`, path14]) {
|
|
26969
27850
|
if (!existsSync6(candidate))
|
|
26970
27851
|
continue;
|
|
26971
27852
|
if (!secureGeneration(candidate))
|
|
@@ -26973,10 +27854,10 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
|
|
|
26973
27854
|
const noFollow = "O_NOFOLLOW" in constants ? constants.O_NOFOLLOW : 0;
|
|
26974
27855
|
const fd = openSync(candidate, constants.O_RDONLY | noFollow);
|
|
26975
27856
|
try {
|
|
26976
|
-
const
|
|
26977
|
-
if (!
|
|
27857
|
+
const stat2 = fstatSync(fd);
|
|
27858
|
+
if (!stat2.isFile())
|
|
26978
27859
|
throw new Error("snapshot source is not a regular file");
|
|
26979
|
-
files.push({ path: candidate, fd, size:
|
|
27860
|
+
files.push({ path: candidate, fd, size: stat2.size });
|
|
26980
27861
|
} catch (error51) {
|
|
26981
27862
|
closeSync(fd);
|
|
26982
27863
|
throw error51;
|
|
@@ -27126,11 +28007,11 @@ function createTraceSampler(emit, throttleMs = DEFAULT_TRACE_SAMPLE_MS) {
|
|
|
27126
28007
|
|
|
27127
28008
|
// src/util/statusFile.ts
|
|
27128
28009
|
import { writeFileSync as writeFileSync4, renameSync as renameSync3 } from "node:fs";
|
|
27129
|
-
function writeStatusFile(
|
|
28010
|
+
function writeStatusFile(path14, snapshot) {
|
|
27130
28011
|
try {
|
|
27131
|
-
const tmp = `${
|
|
28012
|
+
const tmp = `${path14}.tmp`;
|
|
27132
28013
|
writeFileSync4(tmp, JSON.stringify(snapshot));
|
|
27133
|
-
renameSync3(tmp,
|
|
28014
|
+
renameSync3(tmp, path14);
|
|
27134
28015
|
} catch {}
|
|
27135
28016
|
}
|
|
27136
28017
|
|
|
@@ -27812,7 +28693,7 @@ import * as fs7 from "fs";
|
|
|
27812
28693
|
import * as http from "http";
|
|
27813
28694
|
import * as https from "https";
|
|
27814
28695
|
import * as os2 from "os";
|
|
27815
|
-
import * as
|
|
28696
|
+
import * as path14 from "path";
|
|
27816
28697
|
import { URL as URL2 } from "url";
|
|
27817
28698
|
var LOCAL_MESSAGE_REMINDER_PATH = "/__alook/local/message-reminder";
|
|
27818
28699
|
var LOCAL_MESSAGE_REMINDER_BODY_MAX_BYTES = 4 * 1024;
|
|
@@ -27844,15 +28725,15 @@ class CredentialBroker {
|
|
|
27844
28725
|
this.voucherPrefix = config2.voucherPrefix ?? "vch_";
|
|
27845
28726
|
this.clientLabel = config2.clientLabel ?? "cli";
|
|
27846
28727
|
this.headerNames = config2.headerNames ?? DEFAULT_HEADER_NAMES;
|
|
27847
|
-
this.voucherDir = config2.voucherDir ??
|
|
28728
|
+
this.voucherDir = config2.voucherDir ?? path14.join(os2.tmpdir(), "agent-vouchers");
|
|
27848
28729
|
}
|
|
27849
28730
|
mint(agentId, launchId, capabilities2, runnerKey) {
|
|
27850
28731
|
if (!runnerKey)
|
|
27851
28732
|
throw new Error("CredentialBroker.mint: runnerKey is required (per-agent tier-2 credential)");
|
|
27852
28733
|
const voucher = randomVoucher(this.voucherPrefix);
|
|
27853
|
-
const dir =
|
|
28734
|
+
const dir = path14.join(this.voucherDir, sanitizeIdSegment(agentId));
|
|
27854
28735
|
fs7.mkdirSync(dir, { recursive: true });
|
|
27855
|
-
const voucherFile =
|
|
28736
|
+
const voucherFile = path14.join(dir, `${sanitizeIdSegment(launchId)}.token`);
|
|
27856
28737
|
fs7.writeFileSync(voucherFile, voucher, { mode: 384 });
|
|
27857
28738
|
this.registrations.set(voucher, {
|
|
27858
28739
|
agentId,
|
|
@@ -28049,12 +28930,20 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
28049
28930
|
const upstream = new URL2(broker.upstreamBaseUrl);
|
|
28050
28931
|
const upstreamClient = upstream.protocol === "https:" ? https : http;
|
|
28051
28932
|
const onPull = options.onInboxPullResponse;
|
|
28933
|
+
const onAck = options.onInboxAckResponse;
|
|
28052
28934
|
const onProxyRequest = options.onProxyRequest;
|
|
28053
28935
|
const reportInboxPullObservationError = (failure) => {
|
|
28054
28936
|
try {
|
|
28055
28937
|
options.onInboxPullObservationError?.(failure);
|
|
28056
28938
|
} catch {}
|
|
28057
28939
|
};
|
|
28940
|
+
const reportInboxAckObservationError = (failure) => {
|
|
28941
|
+
try {
|
|
28942
|
+
options.onInboxAckObservationError?.(failure);
|
|
28943
|
+
} catch {
|
|
28944
|
+
return;
|
|
28945
|
+
}
|
|
28946
|
+
};
|
|
28058
28947
|
const server = http.createServer((req, res) => {
|
|
28059
28948
|
const pathname = new URL2(req.url ?? "/", "http://placeholder").pathname;
|
|
28060
28949
|
if (pathname.startsWith("/__alook/local/")) {
|
|
@@ -28094,8 +28983,11 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
28094
28983
|
}
|
|
28095
28984
|
const reg = verdict.reg;
|
|
28096
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";
|
|
28097
28987
|
const shouldObserveInboxPull = Boolean(isInboxPull && onPull);
|
|
28988
|
+
const shouldObserveInboxAck = Boolean(isInboxAck && onAck);
|
|
28098
28989
|
let inboxPullObservationToken;
|
|
28990
|
+
let inboxAckObservationToken;
|
|
28099
28991
|
if (shouldObserveInboxPull) {
|
|
28100
28992
|
try {
|
|
28101
28993
|
inboxPullObservationToken = options.onInboxPullStart?.(reg.agentId);
|
|
@@ -28107,6 +28999,17 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
28107
28999
|
});
|
|
28108
29000
|
}
|
|
28109
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
|
+
}
|
|
28110
29013
|
if (onProxyRequest) {
|
|
28111
29014
|
try {
|
|
28112
29015
|
const method = req.method ?? "GET";
|
|
@@ -28124,7 +29027,7 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
28124
29027
|
outHeaders[broker.headerNames.agentId.toLowerCase()] = reg.agentId;
|
|
28125
29028
|
outHeaders[broker.headerNames.client.toLowerCase()] = broker.clientLabel;
|
|
28126
29029
|
outHeaders[broker.headerNames.capabilities.toLowerCase()] = [...reg.capabilities].join(",");
|
|
28127
|
-
if (isInboxPull)
|
|
29030
|
+
if (isInboxPull || isInboxAck)
|
|
28128
29031
|
outHeaders["accept-encoding"] = "identity";
|
|
28129
29032
|
let responded = false;
|
|
28130
29033
|
let upstreamRes;
|
|
@@ -28144,43 +29047,72 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
28144
29047
|
};
|
|
28145
29048
|
res_.on("error", destroyResIfIncomplete);
|
|
28146
29049
|
res_.on("close", destroyResIfIncomplete);
|
|
28147
|
-
if (shouldObserveInboxPull && res_.statusCode !== undefined && res_.statusCode >= 200 && res_.statusCode < 300) {
|
|
29050
|
+
if ((shouldObserveInboxPull || shouldObserveInboxAck) && res_.statusCode !== undefined && res_.statusCode >= 200 && res_.statusCode < 300) {
|
|
28148
29051
|
const chunks = [];
|
|
28149
29052
|
res_.on("data", (chunk2) => chunks.push(chunk2));
|
|
28150
29053
|
res_.on("end", () => {
|
|
28151
29054
|
const body = Buffer.concat(chunks);
|
|
28152
29055
|
const contentEncoding = normalizeContentEncoding(res_.headers["content-encoding"]);
|
|
28153
29056
|
if (contentEncoding !== "identity") {
|
|
28154
|
-
|
|
28155
|
-
|
|
28156
|
-
|
|
28157
|
-
|
|
28158
|
-
|
|
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
|
+
}
|
|
28159
29070
|
} else {
|
|
28160
29071
|
let parsed;
|
|
28161
29072
|
try {
|
|
28162
29073
|
parsed = JSON.parse(body.toString("utf8"));
|
|
28163
29074
|
} catch {
|
|
28164
|
-
|
|
28165
|
-
agentId: reg.agentId,
|
|
28166
|
-
|
|
28167
|
-
contentEncoding
|
|
28168
|
-
}
|
|
29075
|
+
if (shouldObserveInboxPull) {
|
|
29076
|
+
reportInboxPullObservationError({ agentId: reg.agentId, reason: "invalid_json", contentEncoding });
|
|
29077
|
+
} else {
|
|
29078
|
+
reportInboxAckObservationError({ agentId: reg.agentId, reason: "invalid_json", contentEncoding });
|
|
29079
|
+
}
|
|
28169
29080
|
}
|
|
28170
29081
|
if (parsed !== undefined) {
|
|
28171
|
-
if (
|
|
28172
|
-
|
|
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({
|
|
28173
29105
|
agentId: reg.agentId,
|
|
28174
|
-
reason: "
|
|
29106
|
+
reason: "invalid_ack_shape",
|
|
28175
29107
|
contentEncoding
|
|
28176
29108
|
});
|
|
28177
29109
|
} else {
|
|
28178
|
-
const
|
|
28179
|
-
if (
|
|
29110
|
+
const applied = parsed.applied;
|
|
29111
|
+
if (applied.length > 0) {
|
|
28180
29112
|
try {
|
|
28181
|
-
|
|
29113
|
+
onAck(reg.agentId, applied, inboxAckObservationToken);
|
|
28182
29114
|
} catch {
|
|
28183
|
-
|
|
29115
|
+
reportInboxAckObservationError({
|
|
28184
29116
|
agentId: reg.agentId,
|
|
28185
29117
|
reason: "observer_failed",
|
|
28186
29118
|
contentEncoding
|
|
@@ -28920,7 +29852,7 @@ function runtimeModelName(config2) {
|
|
|
28920
29852
|
// agent-driver/dist/provider-quota.js
|
|
28921
29853
|
import { execFile } from "node:child_process";
|
|
28922
29854
|
import { readFile } from "node:fs/promises";
|
|
28923
|
-
import { homedir as
|
|
29855
|
+
import { homedir as homedir5 } from "node:os";
|
|
28924
29856
|
import { join as join11 } from "node:path";
|
|
28925
29857
|
import { promisify } from "node:util";
|
|
28926
29858
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
@@ -28949,7 +29881,7 @@ async function claudeCredentials(options) {
|
|
|
28949
29881
|
} catch {}
|
|
28950
29882
|
}
|
|
28951
29883
|
const env = options.env ?? process.env;
|
|
28952
|
-
const root = env.CLAUDE_CONFIG_DIR || join11(options.home ??
|
|
29884
|
+
const root = env.CLAUDE_CONFIG_DIR || join11(options.home ?? homedir5(), ".claude");
|
|
28953
29885
|
try {
|
|
28954
29886
|
const value = options.readCredentialsFile ? await options.readCredentialsFile(join11(root, ".credentials.json")) : await readFile(join11(root, ".credentials.json"), "utf8");
|
|
28955
29887
|
return parseCredentials(value);
|
|
@@ -29063,13 +29995,16 @@ function scrubRuntimeErrorDiagnosticText(value) {
|
|
|
29063
29995
|
// src/drivers/systemPrompt.ts
|
|
29064
29996
|
var CLI = "$ALOOK_CLI";
|
|
29065
29997
|
var MESSAGE_SEND_STDIN_POLICY = [
|
|
29066
|
-
"
|
|
29998
|
+
"Write each sent message for someone with ADHD who should understand the point in one pass. " + "Match the sender's language.",
|
|
29067
29999
|
"",
|
|
29068
|
-
"- Lead with the
|
|
29069
|
-
"- Keep one message to one topic
|
|
29070
|
-
"-
|
|
29071
|
-
"-
|
|
29072
|
-
"-
|
|
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."
|
|
29073
30008
|
].join(`
|
|
29074
30009
|
`);
|
|
29075
30010
|
function identitySection(config2) {
|
|
@@ -29087,10 +30022,19 @@ function identitySection(config2) {
|
|
|
29087
30022
|
if (owner) {
|
|
29088
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.");
|
|
29089
30024
|
}
|
|
29090
|
-
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.");
|
|
29091
30025
|
return parts.join(`
|
|
29092
30026
|
`);
|
|
29093
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
|
+
}
|
|
29094
30038
|
function cliCommandsSection() {
|
|
29095
30039
|
return [
|
|
29096
30040
|
"## CLI commands",
|
|
@@ -29151,10 +30095,6 @@ function messagingSection() {
|
|
|
29151
30095
|
"",
|
|
29152
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.",
|
|
29153
30097
|
"",
|
|
29154
|
-
"#### Message body",
|
|
29155
|
-
"",
|
|
29156
|
-
MESSAGE_SEND_STDIN_POLICY,
|
|
29157
|
-
"",
|
|
29158
30098
|
"#### Follow up when a conversation goes quiet",
|
|
29159
30099
|
"",
|
|
29160
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.",
|
|
@@ -29293,7 +30233,6 @@ function criticalRulesSection() {
|
|
|
29293
30233
|
"",
|
|
29294
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.`,
|
|
29295
30235
|
"- **Never expose tokens, keys, or secrets.** Redact credential-like strings from tool output " + "before sharing.",
|
|
29296
|
-
"- **Match the sender's language.** Reply in the language they wrote in.",
|
|
29297
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.`,
|
|
29298
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."
|
|
29299
30238
|
].join(`
|
|
@@ -29390,6 +30329,7 @@ function workspaceMemorySection(config2) {
|
|
|
29390
30329
|
function buildCliSystemPrompt(config2) {
|
|
29391
30330
|
const sections = [
|
|
29392
30331
|
identitySection(config2),
|
|
30332
|
+
goodMessageContentSection(),
|
|
29393
30333
|
cliCommandsSection(),
|
|
29394
30334
|
messagingSection(),
|
|
29395
30335
|
channelTypesSection(),
|
|
@@ -30305,6 +31245,10 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
30305
31245
|
sent = session2.send(input);
|
|
30306
31246
|
if (exactOwner)
|
|
30307
31247
|
this.markPendingDeliveryObserved(exactOwner, input.id);
|
|
31248
|
+
this.log.info("steering message submitted to logical session", {
|
|
31249
|
+
agentId: effect.agentId,
|
|
31250
|
+
mode: effect.mode
|
|
31251
|
+
});
|
|
30308
31252
|
} catch (error51) {
|
|
30309
31253
|
if (exactOwner) {
|
|
30310
31254
|
this.settlePendingDelivery(exactOwner, input.id);
|
|
@@ -30350,7 +31294,6 @@ ${this.opts.wakePromptFooter}` : text2;
|
|
|
30350
31294
|
mode: effect.mode
|
|
30351
31295
|
});
|
|
30352
31296
|
}
|
|
30353
|
-
this.log.info("steering message sent to running agent", { agentId: effect.agentId, mode: effect.mode });
|
|
30354
31297
|
break;
|
|
30355
31298
|
}
|
|
30356
31299
|
case "stop":
|
|
@@ -31396,6 +32339,26 @@ class AgentRouter {
|
|
|
31396
32339
|
return;
|
|
31397
32340
|
}
|
|
31398
32341
|
break;
|
|
32342
|
+
case "agent:event":
|
|
32343
|
+
this.log.info("agent:event received", { agentId: cmd.agentId });
|
|
32344
|
+
try {
|
|
32345
|
+
await this.opts.onBeforeAgent?.(cmd.agentId);
|
|
32346
|
+
this.opts.manager.register(cmd.agentId, {
|
|
32347
|
+
runtimeConfig: cmd.config,
|
|
32348
|
+
launchId: cmd.launchId
|
|
32349
|
+
});
|
|
32350
|
+
this.running.add(cmd.agentId);
|
|
32351
|
+
this.opts.manager.deliver(cmd.agentId, {
|
|
32352
|
+
id: `${cmd.agentId}:event:${cmd.launchId}`,
|
|
32353
|
+
text: cmd.prompt
|
|
32354
|
+
});
|
|
32355
|
+
} catch (err) {
|
|
32356
|
+
this.log.warn("agent:event failed", {
|
|
32357
|
+
agentId: cmd.agentId,
|
|
32358
|
+
err: err instanceof Error ? err.message : String(err)
|
|
32359
|
+
});
|
|
32360
|
+
}
|
|
32361
|
+
break;
|
|
31399
32362
|
case "agent:reset":
|
|
31400
32363
|
await this.runRestartCommand(cmd.agentId, cmd.launchId, "agent:reset", () => this.opts.manager.resetSession(cmd.agentId, {
|
|
31401
32364
|
runtimeConfig: cmd.config,
|
|
@@ -31626,11 +32589,11 @@ function timelineRowHash(line) {
|
|
|
31626
32589
|
}
|
|
31627
32590
|
function timelineFileGeneration(filePath, lines) {
|
|
31628
32591
|
try {
|
|
31629
|
-
const
|
|
31630
|
-
if (!
|
|
32592
|
+
const stat2 = fs9.lstatSync(filePath, { bigint: true });
|
|
32593
|
+
if (!stat2.isFile())
|
|
31631
32594
|
return null;
|
|
31632
32595
|
const digest = createHash2("sha256");
|
|
31633
|
-
digest.update(`${
|
|
32596
|
+
digest.update(`${stat2.dev}:${stat2.ino}:${stat2.size}:${stat2.mtimeNs}:${stat2.ctimeNs}
|
|
31634
32597
|
`);
|
|
31635
32598
|
for (const line of lines)
|
|
31636
32599
|
digest.update(line.text, "utf8").update(`
|
|
@@ -31688,9 +32651,9 @@ function compactLines(input) {
|
|
|
31688
32651
|
}
|
|
31689
32652
|
return suffix;
|
|
31690
32653
|
}
|
|
31691
|
-
function isRealDirectory(
|
|
32654
|
+
function isRealDirectory(path15) {
|
|
31692
32655
|
try {
|
|
31693
|
-
return fs9.lstatSync(
|
|
32656
|
+
return fs9.lstatSync(path15).isDirectory();
|
|
31694
32657
|
} catch {
|
|
31695
32658
|
return false;
|
|
31696
32659
|
}
|
|
@@ -31730,8 +32693,8 @@ function scanTimelineFile(filePath) {
|
|
|
31730
32693
|
let fd = null;
|
|
31731
32694
|
try {
|
|
31732
32695
|
fd = fs9.openSync(filePath, fs9.constants.O_RDONLY | (fs9.constants.O_NOFOLLOW ?? 0));
|
|
31733
|
-
const
|
|
31734
|
-
if (!
|
|
32696
|
+
const stat2 = fs9.fstatSync(fd);
|
|
32697
|
+
if (!stat2.isFile())
|
|
31735
32698
|
return null;
|
|
31736
32699
|
const chunk2 = Buffer.allocUnsafe(TIMELINE_READ_CHUNK_BYTES);
|
|
31737
32700
|
const newest = [];
|
|
@@ -31744,9 +32707,9 @@ function scanTimelineFile(filePath) {
|
|
|
31744
32707
|
let oversized = false;
|
|
31745
32708
|
let stop = false;
|
|
31746
32709
|
let discardIncompleteTail = false;
|
|
31747
|
-
if (
|
|
32710
|
+
if (stat2.size > 0) {
|
|
31748
32711
|
const last = Buffer.allocUnsafe(1);
|
|
31749
|
-
fs9.readSync(fd, last, 0, 1,
|
|
32712
|
+
fs9.readSync(fd, last, 0, 1, stat2.size - 1);
|
|
31750
32713
|
discardIncompleteTail = last[0] !== 10;
|
|
31751
32714
|
}
|
|
31752
32715
|
const resetPhysicalLine = () => {
|
|
@@ -31805,7 +32768,7 @@ function scanTimelineFile(filePath) {
|
|
|
31805
32768
|
}
|
|
31806
32769
|
resetPhysicalLine();
|
|
31807
32770
|
};
|
|
31808
|
-
let position =
|
|
32771
|
+
let position = stat2.size;
|
|
31809
32772
|
while (position > 0 && !stop) {
|
|
31810
32773
|
const start = Math.max(0, position - chunk2.length);
|
|
31811
32774
|
const requested = position - start;
|
|
@@ -31957,11 +32920,11 @@ function readResumeControlState(timelineDir) {
|
|
|
31957
32920
|
let fd = null;
|
|
31958
32921
|
try {
|
|
31959
32922
|
fd = fs9.openSync(filePath, fs9.constants.O_RDONLY | (fs9.constants.O_NOFOLLOW ?? 0));
|
|
31960
|
-
const
|
|
31961
|
-
if (!
|
|
32923
|
+
const stat2 = fs9.fstatSync(fd);
|
|
32924
|
+
if (!stat2.isFile() || stat2.size <= 0 || stat2.size > RESUME_CONTROL_MAX_BYTES) {
|
|
31962
32925
|
return { kind: "invalid" };
|
|
31963
32926
|
}
|
|
31964
|
-
const bounded = Buffer.allocUnsafe(
|
|
32927
|
+
const bounded = Buffer.allocUnsafe(stat2.size + 1);
|
|
31965
32928
|
let bytesRead = 0;
|
|
31966
32929
|
while (bytesRead < bounded.length) {
|
|
31967
32930
|
const count = fs9.readSync(fd, bounded, bytesRead, bounded.length - bytesRead, bytesRead);
|
|
@@ -31969,7 +32932,7 @@ function readResumeControlState(timelineDir) {
|
|
|
31969
32932
|
break;
|
|
31970
32933
|
bytesRead += count;
|
|
31971
32934
|
}
|
|
31972
|
-
if (bytesRead !==
|
|
32935
|
+
if (bytesRead !== stat2.size)
|
|
31973
32936
|
return { kind: "invalid" };
|
|
31974
32937
|
const raw = bounded.subarray(0, bytesRead).toString("utf8");
|
|
31975
32938
|
const value = JSON.parse(raw);
|
|
@@ -32895,7 +33858,7 @@ class MessageReminderScheduler {
|
|
|
32895
33858
|
|
|
32896
33859
|
// src/manager/agentDriverHost.ts
|
|
32897
33860
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
32898
|
-
import { homedir as
|
|
33861
|
+
import { homedir as homedir6 } from "node:os";
|
|
32899
33862
|
import { join as join13 } from "node:path";
|
|
32900
33863
|
|
|
32901
33864
|
// src/drivers/gitIdentityEnv.ts
|
|
@@ -33021,7 +33984,7 @@ function createDaemonAgentDriverHost(ctx, onRawLine) {
|
|
|
33021
33984
|
hostUser: readHostGitIdentity() ?? undefined
|
|
33022
33985
|
}),
|
|
33023
33986
|
platformProtected: {
|
|
33024
|
-
ALOOK_HOME: process.env.ALOOK_HOME ?? join13(
|
|
33987
|
+
ALOOK_HOME: process.env.ALOOK_HOME ?? join13(homedir6(), ".alook"),
|
|
33025
33988
|
ALOOK_ID: ctx.agentId,
|
|
33026
33989
|
ALOOK_CLI: ctx.agentCliPath,
|
|
33027
33990
|
ALOOK_SERVER_URL: ctx.config.serverUrl,
|
|
@@ -33342,13 +34305,13 @@ function createRuntimeRawLineTap(args) {
|
|
|
33342
34305
|
const maxBytes = args.maxBytes ?? RUNTIME_RAW_TRACE_MAX_BYTES;
|
|
33343
34306
|
const sinks = new Map;
|
|
33344
34307
|
const warned = new Set;
|
|
33345
|
-
const warnOnce = (agentId,
|
|
34308
|
+
const warnOnce = (agentId, path15, operation, error51) => {
|
|
33346
34309
|
if (warned.has(agentId))
|
|
33347
34310
|
return;
|
|
33348
34311
|
warned.add(agentId);
|
|
33349
34312
|
args.logger.warn("runtime raw trace sink failed", {
|
|
33350
34313
|
agentId,
|
|
33351
|
-
path:
|
|
34314
|
+
path: path15,
|
|
33352
34315
|
operation,
|
|
33353
34316
|
error: error51 instanceof Error ? error51.message : String(error51)
|
|
33354
34317
|
});
|
|
@@ -33357,10 +34320,10 @@ function createRuntimeRawLineTap(args) {
|
|
|
33357
34320
|
if (!args.enabledAgentIds.has(agentId))
|
|
33358
34321
|
return;
|
|
33359
34322
|
const encodedAgentId = encodeURIComponent(agentId).replace(/\./g, "%2E");
|
|
33360
|
-
const
|
|
34323
|
+
const path15 = `${traceDir}/runtime-raw-events-${encodedAgentId}.jsonl`;
|
|
33361
34324
|
const serializedBytes = Buffer.byteLength(line, "utf8") + 1;
|
|
33362
34325
|
if (serializedBytes > maxBytes) {
|
|
33363
|
-
warnOnce(agentId,
|
|
34326
|
+
warnOnce(agentId, path15, "oversize", new Error(`raw line is ${serializedBytes} bytes; max is ${maxBytes}`));
|
|
33364
34327
|
return;
|
|
33365
34328
|
}
|
|
33366
34329
|
let sink = sinks.get(agentId);
|
|
@@ -33368,12 +34331,12 @@ function createRuntimeRawLineTap(args) {
|
|
|
33368
34331
|
try {
|
|
33369
34332
|
mkdirSync8(traceDir, { recursive: true });
|
|
33370
34333
|
} catch (error51) {
|
|
33371
|
-
warnOnce(agentId,
|
|
34334
|
+
warnOnce(agentId, path15, "mkdir", error51);
|
|
33372
34335
|
}
|
|
33373
|
-
sink = createRotatingFileSink(
|
|
34336
|
+
sink = createRotatingFileSink(path15, maxBytes, {
|
|
33374
34337
|
mode: 384,
|
|
33375
34338
|
hardMaxBytes: true,
|
|
33376
|
-
onError: ({ operation, error: error51 }) => warnOnce(agentId,
|
|
34339
|
+
onError: ({ operation, error: error51 }) => warnOnce(agentId, path15, operation, error51)
|
|
33377
34340
|
});
|
|
33378
34341
|
sinks.set(agentId, sink);
|
|
33379
34342
|
}
|
|
@@ -33465,7 +34428,7 @@ function createBuiltinDaemonSessionFactory(onRuntimeRawLine) {
|
|
|
33465
34428
|
}
|
|
33466
34429
|
async function createDaemon(opts) {
|
|
33467
34430
|
const log2 = opts.logger ?? createLogger2({ header: "@alook/daemon" });
|
|
33468
|
-
const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${
|
|
34431
|
+
const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${homedir7()}/.alook`) + "/daemon";
|
|
33469
34432
|
const workingDirectoryBase = opts.workingDirectoryBase ?? fallbackBase;
|
|
33470
34433
|
const workdirFor = (agentId) => `${workingDirectoryBase}/${agentId}`;
|
|
33471
34434
|
const dailyTokenUsage2 = new DailyTokenUsageStore(workingDirectoryBase);
|
|
@@ -33544,19 +34507,24 @@ async function createDaemon(opts) {
|
|
|
33544
34507
|
const broker = new CredentialBroker({ upstreamBaseUrl: opts.serverUrl });
|
|
33545
34508
|
const proxy = await startCredentialProxy(broker, {
|
|
33546
34509
|
onInboxPullStart: (agentId) => ({
|
|
33547
|
-
modelSeenGeneration: channelRef?.modelSeenGeneration(agentId),
|
|
33548
34510
|
owner: managerRef?.timelineTurnOwner(agentId) ?? null
|
|
33549
34511
|
}),
|
|
33550
34512
|
onInboxPullResponse: (agentId, messages, observationToken) => {
|
|
33551
34513
|
const token = observationToken && typeof observationToken === "object" ? observationToken : null;
|
|
33552
34514
|
timeline2.recordInboxPull(agentId, token?.owner ?? null, messages);
|
|
33553
|
-
if (typeof token?.modelSeenGeneration === "number") {
|
|
33554
|
-
channelRef?.recordModelSeen(agentId, messages, token.modelSeenGeneration);
|
|
33555
|
-
}
|
|
33556
34515
|
},
|
|
33557
34516
|
onInboxPullObservationError: ({ agentId, reason, contentEncoding }) => {
|
|
33558
34517
|
log2.warn("inbox pull timeline observation failed", { agentId, reason, contentEncoding });
|
|
33559
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
|
+
},
|
|
33560
34528
|
onMessageReminderArm: (input) => reminderSchedulerRef?.arm(input) ?? { armed: false, reason: "reminder_scheduler_unavailable" },
|
|
33561
34529
|
onProxyRequest: (agentId, method, pathname, metadata) => {
|
|
33562
34530
|
const subcommand = deriveAuditLogSubcommand(pathname, method);
|
|
@@ -34171,12 +35139,12 @@ async function readPinnedJsonFile(args) {
|
|
|
34171
35139
|
}
|
|
34172
35140
|
}
|
|
34173
35141
|
fd = openSync3(args.path, constants3.O_RDONLY | noFollow);
|
|
34174
|
-
const
|
|
34175
|
-
if (!
|
|
35142
|
+
const stat2 = fstatSync3(fd);
|
|
35143
|
+
if (!stat2.isFile())
|
|
34176
35144
|
return { value: null, warnings: ["source_unavailable"] };
|
|
34177
|
-
if (
|
|
35145
|
+
if (stat2.size > args.maxBytes)
|
|
34178
35146
|
return { value: null, warnings: ["line_too_long"] };
|
|
34179
|
-
const bytes = readPinnedBytes(fd,
|
|
35147
|
+
const bytes = readPinnedBytes(fd, stat2.size);
|
|
34180
35148
|
try {
|
|
34181
35149
|
return { value: JSON.parse(bytes.toString("utf8")), warnings: [] };
|
|
34182
35150
|
} catch {
|
|
@@ -34254,7 +35222,7 @@ var DAEMON_LOG_DIAGNOSTIC_POLICY = [
|
|
|
34254
35222
|
reason: string5(32, { values: ["turn_end", "stopped", "terminate_stalled", "exit"] }),
|
|
34255
35223
|
sessionId: string5(256, { scrub: true })
|
|
34256
35224
|
} },
|
|
34257
|
-
{ header: "@alook/daemon:manager", message: "steering message
|
|
35225
|
+
{ header: "@alook/daemon:manager", message: "steering message submitted to logical session", scope: "target", fields: {
|
|
34258
35226
|
agentId: AGENT,
|
|
34259
35227
|
mode: string5(8, { values: ["busy", "idle"] })
|
|
34260
35228
|
} },
|
|
@@ -34809,7 +35777,7 @@ import { createHash as createHash4, randomBytes as randomBytes7 } from "node:cry
|
|
|
34809
35777
|
import {
|
|
34810
35778
|
chmodSync as chmodSync2,
|
|
34811
35779
|
closeSync as closeSync4,
|
|
34812
|
-
createReadStream,
|
|
35780
|
+
createReadStream as createReadStream3,
|
|
34813
35781
|
existsSync as existsSync7,
|
|
34814
35782
|
fsyncSync as fsyncSync2,
|
|
34815
35783
|
lstatSync as lstatSync5,
|
|
@@ -34832,7 +35800,7 @@ class CoordinatorError extends Error {
|
|
|
34832
35800
|
function defaultFsOps() {
|
|
34833
35801
|
return {
|
|
34834
35802
|
randomSuffix: () => randomBytes7(12).toString("hex"),
|
|
34835
|
-
open: (
|
|
35803
|
+
open: (path15, flags, mode) => openSync4(path15, flags, mode),
|
|
34836
35804
|
write: (fd, bytes) => {
|
|
34837
35805
|
writeSync(fd, bytes);
|
|
34838
35806
|
},
|
|
@@ -34845,10 +35813,10 @@ function defaultFsOps() {
|
|
|
34845
35813
|
rename: (from, to) => {
|
|
34846
35814
|
renameSync5(from, to);
|
|
34847
35815
|
},
|
|
34848
|
-
fsyncDirectory: (
|
|
35816
|
+
fsyncDirectory: (path15) => {
|
|
34849
35817
|
if (process.platform === "win32")
|
|
34850
35818
|
return;
|
|
34851
|
-
const fd = openSync4(
|
|
35819
|
+
const fd = openSync4(path15, "r");
|
|
34852
35820
|
try {
|
|
34853
35821
|
fsyncSync2(fd);
|
|
34854
35822
|
} finally {
|
|
@@ -34899,8 +35867,8 @@ function createDiagnosticReportCoordinator(args) {
|
|
|
34899
35867
|
const sidecarPath = (reportId) => join15(dir, `report-${reportId}.json`);
|
|
34900
35868
|
const ensureDir = () => {
|
|
34901
35869
|
if (existsSync7(dir)) {
|
|
34902
|
-
const
|
|
34903
|
-
if (!
|
|
35870
|
+
const stat2 = lstatSync5(dir);
|
|
35871
|
+
if (!stat2.isDirectory() || stat2.isSymbolicLink())
|
|
34904
35872
|
throw new CoordinatorError("local_artifact_invalid");
|
|
34905
35873
|
if (process.platform !== "win32")
|
|
34906
35874
|
chmodSync2(dir, 448);
|
|
@@ -34913,11 +35881,11 @@ function createDiagnosticReportCoordinator(args) {
|
|
|
34913
35881
|
args.logger?.warn("diagnostic local artifact invalid", { reportId, code: "local_artifact_invalid" });
|
|
34914
35882
|
} catch {}
|
|
34915
35883
|
};
|
|
34916
|
-
const removeExact = (
|
|
35884
|
+
const removeExact = (path15) => {
|
|
34917
35885
|
try {
|
|
34918
|
-
const
|
|
34919
|
-
if (
|
|
34920
|
-
unlinkSync6(
|
|
35886
|
+
const stat2 = lstatSync5(path15);
|
|
35887
|
+
if (stat2.isFile() && !stat2.isSymbolicLink())
|
|
35888
|
+
unlinkSync6(path15);
|
|
34921
35889
|
} catch {}
|
|
34922
35890
|
};
|
|
34923
35891
|
const cleanup = (reportId) => {
|
|
@@ -34955,12 +35923,12 @@ function createDiagnosticReportCoordinator(args) {
|
|
|
34955
35923
|
checkpoint(sidecar.phase === "collecting" ? "collecting_dir_fsynced" : "ready_dir_fsynced");
|
|
34956
35924
|
};
|
|
34957
35925
|
const committedArchive = (reportId) => {
|
|
34958
|
-
const
|
|
35926
|
+
const path15 = archivePath(reportId);
|
|
34959
35927
|
try {
|
|
34960
|
-
const
|
|
34961
|
-
if (!
|
|
35928
|
+
const stat2 = lstatSync5(path15);
|
|
35929
|
+
if (!stat2.isFile() || stat2.isSymbolicLink())
|
|
34962
35930
|
return null;
|
|
34963
|
-
const bytes = readFileSync6(
|
|
35931
|
+
const bytes = readFileSync6(path15);
|
|
34964
35932
|
return { sizeBytes: bytes.byteLength, sha256: createHash4("sha256").update(bytes).digest("hex") };
|
|
34965
35933
|
} catch {
|
|
34966
35934
|
return null;
|
|
@@ -35021,7 +35989,7 @@ function createDiagnosticReportCoordinator(args) {
|
|
|
35021
35989
|
if (stopped)
|
|
35022
35990
|
throw new CoordinatorError("coordinator_shutdown");
|
|
35023
35991
|
checkpoint("before_upload");
|
|
35024
|
-
const result = await args.transport.upload({ reportId: sidecar.reportId, sizeBytes: sidecar.sizeBytes, sha256: sidecar.sha256 },
|
|
35992
|
+
const result = await args.transport.upload({ reportId: sidecar.reportId, sizeBytes: sidecar.sizeBytes, sha256: sidecar.sha256 }, createReadStream3(archivePath(sidecar.reportId)));
|
|
35025
35993
|
checkpoint("after_upload");
|
|
35026
35994
|
if (result.kind === "terminal") {
|
|
35027
35995
|
cleanup(sidecar.reportId);
|
|
@@ -35085,12 +36053,12 @@ function createDiagnosticReportCoordinator(args) {
|
|
|
35085
36053
|
return uploadReady(ready);
|
|
35086
36054
|
};
|
|
35087
36055
|
const readSidecar = (reportId) => {
|
|
35088
|
-
const
|
|
36056
|
+
const path15 = sidecarPath(reportId);
|
|
35089
36057
|
try {
|
|
35090
|
-
const
|
|
35091
|
-
if (!
|
|
36058
|
+
const stat2 = lstatSync5(path15);
|
|
36059
|
+
if (!stat2.isFile() || stat2.isSymbolicLink())
|
|
35092
36060
|
return null;
|
|
35093
|
-
return parseSidecar(JSON.parse(readFileSync6(
|
|
36061
|
+
return parseSidecar(JSON.parse(readFileSync6(path15, "utf8")));
|
|
35094
36062
|
} catch {
|
|
35095
36063
|
return null;
|
|
35096
36064
|
}
|
|
@@ -35178,9 +36146,9 @@ function createDiagnosticReportCoordinator(args) {
|
|
|
35178
36146
|
}
|
|
35179
36147
|
// src/diagnostics/httpTransport.ts
|
|
35180
36148
|
import { Readable as Readable2 } from "node:stream";
|
|
35181
|
-
function endpoint(serverUrl,
|
|
36149
|
+
function endpoint(serverUrl, path15) {
|
|
35182
36150
|
const base = serverUrl.endsWith("/") ? serverUrl : `${serverUrl}/`;
|
|
35183
|
-
return new URL(
|
|
36151
|
+
return new URL(path15.replace(/^\//, ""), base).toString();
|
|
35184
36152
|
}
|
|
35185
36153
|
async function strictOutcome(response, allowed) {
|
|
35186
36154
|
try {
|
|
@@ -35244,29 +36212,29 @@ function createDiagnosticHttpTransport(args) {
|
|
|
35244
36212
|
// src/cli/daemonUpdate.ts
|
|
35245
36213
|
import * as crypto4 from "node:crypto";
|
|
35246
36214
|
import * as fs10 from "node:fs";
|
|
35247
|
-
import * as
|
|
36215
|
+
import * as path15 from "node:path";
|
|
35248
36216
|
import { spawn as spawn2 } from "node:child_process";
|
|
35249
36217
|
var UPDATE_INTENT_SCHEMA_VERSION = 1;
|
|
35250
36218
|
var UPDATE_LOG_MAX_BYTES = 512 * 1024;
|
|
35251
36219
|
var UPDATE_LOG_KEEP_BYTES = 256 * 1024;
|
|
35252
36220
|
var REQUEST_ID_PATTERN = /^[A-Za-z0-9_-]{16,128}$/;
|
|
35253
36221
|
function intentPath(baseDir, machineId) {
|
|
35254
|
-
return
|
|
36222
|
+
return path15.join(daemonDirById(baseDir, machineId), "update-intent.json");
|
|
35255
36223
|
}
|
|
35256
36224
|
function updateLogPath(baseDir, machineId) {
|
|
35257
|
-
return
|
|
36225
|
+
return path15.join(daemonDirById(baseDir, machineId), "update.log");
|
|
35258
36226
|
}
|
|
35259
36227
|
function updatePackageMapPath(baseDir, machineId) {
|
|
35260
|
-
return
|
|
36228
|
+
return path15.join(daemonDirById(baseDir, machineId), "update-package-map.json");
|
|
35261
36229
|
}
|
|
35262
36230
|
function ensurePrivateDir(dir) {
|
|
35263
36231
|
fs10.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
35264
36232
|
fs10.chmodSync(dir, 448);
|
|
35265
36233
|
}
|
|
35266
36234
|
function writePrivateJsonAtomic(filePath, value) {
|
|
35267
|
-
const dir =
|
|
36235
|
+
const dir = path15.dirname(filePath);
|
|
35268
36236
|
ensurePrivateDir(dir);
|
|
35269
|
-
const tempPath =
|
|
36237
|
+
const tempPath = path15.join(dir, `.${path15.basename(filePath)}.${process.pid}.${crypto4.randomBytes(8).toString("hex")}.tmp`);
|
|
35270
36238
|
let fd = fs10.openSync(tempPath, "wx", 384);
|
|
35271
36239
|
try {
|
|
35272
36240
|
fs10.writeFileSync(fd, JSON.stringify(value));
|
|
@@ -35291,7 +36259,7 @@ function scrub(value) {
|
|
|
35291
36259
|
}
|
|
35292
36260
|
function appendUpdateLog(baseDir, machineId, event, fields = {}) {
|
|
35293
36261
|
const filePath = updateLogPath(baseDir, machineId);
|
|
35294
|
-
ensurePrivateDir(
|
|
36262
|
+
ensurePrivateDir(path15.dirname(filePath));
|
|
35295
36263
|
try {
|
|
35296
36264
|
if (fs10.existsSync(filePath) && fs10.statSync(filePath).size > UPDATE_LOG_MAX_BYTES) {
|
|
35297
36265
|
const data = fs10.readFileSync(filePath);
|
|
@@ -35318,8 +36286,8 @@ function tuplesEqual(value, expected) {
|
|
|
35318
36286
|
}
|
|
35319
36287
|
function readIntent(baseDir, machineId) {
|
|
35320
36288
|
const filePath = intentPath(baseDir, machineId);
|
|
35321
|
-
const
|
|
35322
|
-
if (!
|
|
36289
|
+
const stat2 = fs10.lstatSync(filePath);
|
|
36290
|
+
if (!stat2.isFile())
|
|
35323
36291
|
throw new Error("unsafe daemon update intent type");
|
|
35324
36292
|
fs10.chmodSync(filePath, 384);
|
|
35325
36293
|
const value = JSON.parse(fs10.readFileSync(filePath, "utf8"));
|
|
@@ -35334,12 +36302,81 @@ function removeIntentIfMatches(baseDir, machineId, requestId) {
|
|
|
35334
36302
|
fs10.unlinkSync(intentPath(baseDir, machineId));
|
|
35335
36303
|
} catch {}
|
|
35336
36304
|
}
|
|
35337
|
-
|
|
35338
|
-
|
|
35339
|
-
|
|
35340
|
-
|
|
36305
|
+
var defaultNpmLaunchFileProbe = {
|
|
36306
|
+
isFile(filePath) {
|
|
36307
|
+
try {
|
|
36308
|
+
return fs10.statSync(filePath).isFile();
|
|
36309
|
+
} catch {
|
|
36310
|
+
return false;
|
|
36311
|
+
}
|
|
36312
|
+
},
|
|
36313
|
+
isExecutable(filePath) {
|
|
36314
|
+
try {
|
|
36315
|
+
fs10.accessSync(filePath, fs10.constants.X_OK);
|
|
36316
|
+
return true;
|
|
36317
|
+
} catch {
|
|
36318
|
+
return false;
|
|
36319
|
+
}
|
|
35341
36320
|
}
|
|
35342
|
-
|
|
36321
|
+
};
|
|
36322
|
+
function pathEnvironment(env, platform) {
|
|
36323
|
+
if (platform !== "win32")
|
|
36324
|
+
return env.PATH;
|
|
36325
|
+
const entry = Object.entries(env).find(([key]) => key.toLowerCase() === "path");
|
|
36326
|
+
return entry?.[1];
|
|
36327
|
+
}
|
|
36328
|
+
function launchFromNpmPath(args) {
|
|
36329
|
+
const pathApi = args.platform === "win32" ? path15.win32 : path15.posix;
|
|
36330
|
+
if (!pathApi.isAbsolute(args.npmPath) || !args.probe.isFile(args.npmPath))
|
|
36331
|
+
return null;
|
|
36332
|
+
const extension = pathApi.extname(args.npmPath).toLowerCase();
|
|
36333
|
+
if ([".js", ".cjs", ".mjs"].includes(extension)) {
|
|
36334
|
+
return { file: args.nodePath, prefixArgs: [args.npmPath] };
|
|
36335
|
+
}
|
|
36336
|
+
if (args.platform === "win32" && [".cmd", ".bat"].includes(extension)) {
|
|
36337
|
+
const cliPath = pathApi.join(pathApi.dirname(args.npmPath), "node_modules", "npm", "bin", "npm-cli.js");
|
|
36338
|
+
return args.probe.isFile(cliPath) ? { file: args.nodePath, prefixArgs: [cliPath] } : null;
|
|
36339
|
+
}
|
|
36340
|
+
if (args.requireExecutable && !args.probe.isExecutable(args.npmPath))
|
|
36341
|
+
return null;
|
|
36342
|
+
return { file: args.npmPath, prefixArgs: [] };
|
|
36343
|
+
}
|
|
36344
|
+
function resolveNpmLaunchCommand(options = {}) {
|
|
36345
|
+
const env = options.env ?? process.env;
|
|
36346
|
+
const platform = options.platform ?? process.platform;
|
|
36347
|
+
const nodePath = options.nodePath ?? process.execPath;
|
|
36348
|
+
const probe = options.probe ?? defaultNpmLaunchFileProbe;
|
|
36349
|
+
const inherited = options.npmExecPath ?? env.npm_execpath;
|
|
36350
|
+
if (inherited) {
|
|
36351
|
+
const launch = launchFromNpmPath({
|
|
36352
|
+
npmPath: inherited,
|
|
36353
|
+
platform,
|
|
36354
|
+
nodePath,
|
|
36355
|
+
probe,
|
|
36356
|
+
requireExecutable: platform !== "win32"
|
|
36357
|
+
});
|
|
36358
|
+
if (launch)
|
|
36359
|
+
return launch;
|
|
36360
|
+
}
|
|
36361
|
+
const pathApi = platform === "win32" ? path15.win32 : path15.posix;
|
|
36362
|
+
const names = platform === "win32" ? ["npm.exe", "npm.cmd", "npm.bat", "npm"] : ["npm"];
|
|
36363
|
+
const pathValue = pathEnvironment(env, platform);
|
|
36364
|
+
for (const directory of pathValue?.split(pathApi.delimiter) ?? []) {
|
|
36365
|
+
if (!directory || !pathApi.isAbsolute(directory))
|
|
36366
|
+
continue;
|
|
36367
|
+
for (const name of names) {
|
|
36368
|
+
const launch = launchFromNpmPath({
|
|
36369
|
+
npmPath: pathApi.join(directory, name),
|
|
36370
|
+
platform,
|
|
36371
|
+
nodePath,
|
|
36372
|
+
probe,
|
|
36373
|
+
requireExecutable: platform !== "win32"
|
|
36374
|
+
});
|
|
36375
|
+
if (launch)
|
|
36376
|
+
return launch;
|
|
36377
|
+
}
|
|
36378
|
+
}
|
|
36379
|
+
throw new Error("npm launch context unavailable and no safe npm executable was found on PATH; daemon remains online");
|
|
35343
36380
|
}
|
|
35344
36381
|
function readTestPackageMap(baseDir, machineId) {
|
|
35345
36382
|
if (true)
|
|
@@ -35347,10 +36384,10 @@ function readTestPackageMap(baseDir, machineId) {
|
|
|
35347
36384
|
const filePath = updatePackageMapPath(baseDir, machineId);
|
|
35348
36385
|
if (!fs10.existsSync(filePath))
|
|
35349
36386
|
return null;
|
|
35350
|
-
const
|
|
35351
|
-
if (!
|
|
36387
|
+
const stat2 = fs10.lstatSync(filePath);
|
|
36388
|
+
if (!stat2.isFile())
|
|
35352
36389
|
throw new Error("unsafe daemon update package map type");
|
|
35353
|
-
if (process.platform !== "win32" && (
|
|
36390
|
+
if (process.platform !== "win32" && (stat2.mode & 63) !== 0) {
|
|
35354
36391
|
throw new Error("daemon update package map must be mode 0600");
|
|
35355
36392
|
}
|
|
35356
36393
|
const parsed = JSON.parse(fs10.readFileSync(filePath, "utf8"));
|
|
@@ -35360,7 +36397,7 @@ function readTestPackageMap(baseDir, machineId) {
|
|
|
35360
36397
|
for (const [key, value] of Object.entries(parsed)) {
|
|
35361
36398
|
if (key !== "latest" && !parseReleaseVersion(key))
|
|
35362
36399
|
throw new Error("invalid daemon update package map key");
|
|
35363
|
-
if (typeof value !== "string" || !
|
|
36400
|
+
if (typeof value !== "string" || !path15.isAbsolute(value))
|
|
35364
36401
|
throw new Error("invalid daemon update package map value");
|
|
35365
36402
|
result[key] = value;
|
|
35366
36403
|
}
|
|
@@ -35374,9 +36411,9 @@ function packageSpec(baseDir, machineId, version3) {
|
|
|
35374
36411
|
}
|
|
35375
36412
|
function fixedNpmArgs(args) {
|
|
35376
36413
|
return [
|
|
35377
|
-
args.npmPath,
|
|
35378
36414
|
"exec",
|
|
35379
36415
|
"--yes",
|
|
36416
|
+
"--no-audit",
|
|
35380
36417
|
`--package=${args.packageSpec}`,
|
|
35381
36418
|
"--",
|
|
35382
36419
|
"alook-daemon",
|
|
@@ -35407,7 +36444,13 @@ function createDaemonSelfUpdateHandler(context, deps = {}) {
|
|
|
35407
36444
|
const current = pidTuple(readPidFile(pidfilePathById(context.baseDir, context.machineId)));
|
|
35408
36445
|
if (!current || current.pid !== context.pid || current.machineId !== context.machineId || current.startedAt !== context.startedAt || current.ownerToken !== context.ownerToken)
|
|
35409
36446
|
throw new Error("daemon ownership changed before update launch");
|
|
35410
|
-
const
|
|
36447
|
+
const npmLaunch = resolveNpmLaunchCommand({
|
|
36448
|
+
npmExecPath: deps.npmExecPath,
|
|
36449
|
+
env: deps.npmLaunchEnv,
|
|
36450
|
+
platform: deps.npmLaunchPlatform,
|
|
36451
|
+
nodePath: deps.npmLaunchNodePath,
|
|
36452
|
+
probe: deps.npmLaunchFileProbe
|
|
36453
|
+
});
|
|
35411
36454
|
requestId = crypto4.randomUUID();
|
|
35412
36455
|
const intent = {
|
|
35413
36456
|
schemaVersion: UPDATE_INTENT_SCHEMA_VERSION,
|
|
@@ -35417,14 +36460,16 @@ function createDaemonSelfUpdateHandler(context, deps = {}) {
|
|
|
35417
36460
|
writePrivateJsonAtomic(intentPath(context.baseDir, context.machineId), intent);
|
|
35418
36461
|
const logFd = openUpdateLog(context.baseDir, context.machineId);
|
|
35419
36462
|
try {
|
|
35420
|
-
const child = (deps.spawnProcess ?? spawn2)(
|
|
35421
|
-
|
|
35422
|
-
|
|
35423
|
-
|
|
35424
|
-
|
|
35425
|
-
|
|
35426
|
-
|
|
35427
|
-
|
|
36463
|
+
const child = (deps.spawnProcess ?? spawn2)(npmLaunch.file, [
|
|
36464
|
+
...npmLaunch.prefixArgs,
|
|
36465
|
+
...fixedNpmArgs({
|
|
36466
|
+
packageSpec: packageSpec(context.baseDir, context.machineId, "latest"),
|
|
36467
|
+
command: "replace",
|
|
36468
|
+
machineId: context.machineId,
|
|
36469
|
+
baseDir: context.baseDir,
|
|
36470
|
+
requestId
|
|
36471
|
+
})
|
|
36472
|
+
], {
|
|
35428
36473
|
detached: true,
|
|
35429
36474
|
shell: false,
|
|
35430
36475
|
stdio: ["ignore", logFd, logFd]
|
|
@@ -35465,14 +36510,16 @@ function removeOldPidfileIfMatches(baseDir, intent) {
|
|
|
35465
36510
|
async function runPinnedResume(args) {
|
|
35466
36511
|
const fd = openUpdateLog(args.baseDir, args.machineId);
|
|
35467
36512
|
try {
|
|
35468
|
-
const child = spawn2(
|
|
35469
|
-
|
|
35470
|
-
|
|
35471
|
-
|
|
35472
|
-
|
|
35473
|
-
|
|
35474
|
-
|
|
35475
|
-
|
|
36513
|
+
const child = spawn2(args.npmLaunch.file, [
|
|
36514
|
+
...args.npmLaunch.prefixArgs,
|
|
36515
|
+
...fixedNpmArgs({
|
|
36516
|
+
packageSpec: packageSpec(args.baseDir, args.machineId, args.version),
|
|
36517
|
+
command: "resume",
|
|
36518
|
+
machineId: args.machineId,
|
|
36519
|
+
baseDir: args.baseDir,
|
|
36520
|
+
requestId: args.requestId
|
|
36521
|
+
})
|
|
36522
|
+
], {
|
|
35476
36523
|
shell: false,
|
|
35477
36524
|
stdio: ["ignore", fd, fd]
|
|
35478
36525
|
});
|
|
@@ -35516,7 +36563,7 @@ async function daemonReplace(opts) {
|
|
|
35516
36563
|
removeIntentIfMatches(baseDir, opts.id, opts.requestId);
|
|
35517
36564
|
throw new Error("daemon ownership changed before replacement");
|
|
35518
36565
|
}
|
|
35519
|
-
const
|
|
36566
|
+
const npmLaunch = resolveNpmLaunchCommand();
|
|
35520
36567
|
const acquired = acquireDaemonReplacementLock({ baseDir, machineId: opts.id, requestId: opts.requestId });
|
|
35521
36568
|
let oldStopped = false;
|
|
35522
36569
|
try {
|
|
@@ -35536,7 +36583,7 @@ async function daemonReplace(opts) {
|
|
|
35536
36583
|
} catch (error51) {
|
|
35537
36584
|
appendUpdateLog(baseDir, opts.id, "replacement_start_failed", { error: error51 });
|
|
35538
36585
|
await runPinnedResume({
|
|
35539
|
-
|
|
36586
|
+
npmLaunch,
|
|
35540
36587
|
version: launch.daemonVersion,
|
|
35541
36588
|
machineId: opts.id,
|
|
35542
36589
|
baseDir,
|
|
@@ -35659,7 +36706,7 @@ async function buildRunnerDiagnosticBundle(args) {
|
|
|
35659
36706
|
function createDaemonProcessLogger(daemonDir, foreground) {
|
|
35660
36707
|
fs11.mkdirSync(daemonDir, { recursive: true, mode: 448 });
|
|
35661
36708
|
fs11.chmodSync(daemonDir, 448);
|
|
35662
|
-
const logPath =
|
|
36709
|
+
const logPath = path16.join(daemonDir, "daemon.log");
|
|
35663
36710
|
let warnedOversize = false;
|
|
35664
36711
|
const sink = createRotatingFileSink(logPath, DAEMON_LOG_MAX_BYTES, {
|
|
35665
36712
|
mode: 384,
|
|
@@ -35895,16 +36942,16 @@ var LEGACY_DAEMON_ID_PATTERN = /^[a-f0-9]{12}$/;
|
|
|
35895
36942
|
var DEFAULT_SERVER_URL = "https://alook.ai";
|
|
35896
36943
|
var DEFAULT_WS_URL = "wss://alook.ai/api/ws/community-daemon";
|
|
35897
36944
|
function resolveDefaultBaseDir() {
|
|
35898
|
-
const root = process.env.ALOOK_PROJECT_ROOT ||
|
|
35899
|
-
return
|
|
36945
|
+
const root = process.env.ALOOK_PROJECT_ROOT || path17.join(homedir8(), ".alook");
|
|
36946
|
+
return path17.join(root, "daemon");
|
|
35900
36947
|
}
|
|
35901
36948
|
var DEFAULT_BASE_DIR = resolveDefaultBaseDir();
|
|
35902
36949
|
var log2 = createLogger2({ header: "@alook/daemon" });
|
|
35903
36950
|
function daemonsDir(baseDir) {
|
|
35904
|
-
return
|
|
36951
|
+
return path17.join(baseDir, "daemons");
|
|
35905
36952
|
}
|
|
35906
36953
|
function daemonDirById(baseDir, id) {
|
|
35907
|
-
return
|
|
36954
|
+
return path17.join(daemonsDir(baseDir), validateDaemonId(id));
|
|
35908
36955
|
}
|
|
35909
36956
|
function validateMachineId(machineId) {
|
|
35910
36957
|
if (!MACHINE_ID_PATTERN.test(machineId))
|
|
@@ -35920,10 +36967,10 @@ function validateDaemonId(id) {
|
|
|
35920
36967
|
return id;
|
|
35921
36968
|
}
|
|
35922
36969
|
function pidfilePathById(baseDir, id) {
|
|
35923
|
-
return
|
|
36970
|
+
return path17.join(daemonDirById(baseDir, id), "daemon.pid");
|
|
35924
36971
|
}
|
|
35925
36972
|
function statusFilePathById(baseDir, id) {
|
|
35926
|
-
return
|
|
36973
|
+
return path17.join(daemonDirById(baseDir, id), "status.json");
|
|
35927
36974
|
}
|
|
35928
36975
|
function isProcessAlive(pid) {
|
|
35929
36976
|
try {
|
|
@@ -35983,9 +37030,9 @@ function syncDirectory(dir) {
|
|
|
35983
37030
|
}
|
|
35984
37031
|
}
|
|
35985
37032
|
function writeExclusive(filePath, value) {
|
|
35986
|
-
const dir =
|
|
37033
|
+
const dir = path17.dirname(filePath);
|
|
35987
37034
|
ensurePrivateDir2(dir);
|
|
35988
|
-
const tempPath =
|
|
37035
|
+
const tempPath = path17.join(dir, `.${path17.basename(filePath)}.${process.pid}.${crypto5.randomBytes(12).toString("hex")}.tmp`);
|
|
35989
37036
|
let fd = fs12.openSync(tempPath, "wx", 384);
|
|
35990
37037
|
try {
|
|
35991
37038
|
fs12.writeFileSync(fd, JSON.stringify(value));
|
|
@@ -36007,9 +37054,9 @@ function writeExclusive(filePath, value) {
|
|
|
36007
37054
|
}
|
|
36008
37055
|
}
|
|
36009
37056
|
function writePrivateJsonAtomic2(filePath, value) {
|
|
36010
|
-
const dir =
|
|
37057
|
+
const dir = path17.dirname(filePath);
|
|
36011
37058
|
ensurePrivateDir2(dir);
|
|
36012
|
-
const tempPath =
|
|
37059
|
+
const tempPath = path17.join(dir, `.${path17.basename(filePath)}.${process.pid}.${crypto5.randomBytes(12).toString("hex")}.tmp`);
|
|
36013
37060
|
let fd = fs12.openSync(tempPath, "wx", 384);
|
|
36014
37061
|
try {
|
|
36015
37062
|
fs12.writeFileSync(fd, JSON.stringify(value));
|
|
@@ -36033,8 +37080,8 @@ function writePrivateJsonAtomic2(filePath, value) {
|
|
|
36033
37080
|
function secureExistingFile(filePath) {
|
|
36034
37081
|
if (!fs12.existsSync(filePath))
|
|
36035
37082
|
return;
|
|
36036
|
-
const
|
|
36037
|
-
if (!
|
|
37083
|
+
const stat2 = fs12.lstatSync(filePath);
|
|
37084
|
+
if (!stat2.isFile())
|
|
36038
37085
|
throw new Error("unsafe daemon ownership file type");
|
|
36039
37086
|
fs12.chmodSync(filePath, 384);
|
|
36040
37087
|
}
|
|
@@ -36096,14 +37143,14 @@ function clearStaleOwnership(filePath, liveError) {
|
|
|
36096
37143
|
} catch {}
|
|
36097
37144
|
}
|
|
36098
37145
|
function replacementLockPathById(baseDir, machineId) {
|
|
36099
|
-
return
|
|
37146
|
+
return path17.join(daemonDirById(baseDir, machineId), "daemon.replace.lock");
|
|
36100
37147
|
}
|
|
36101
37148
|
function readReplacementLock(filePath) {
|
|
36102
37149
|
if (!fs12.existsSync(filePath))
|
|
36103
37150
|
return null;
|
|
36104
37151
|
try {
|
|
36105
|
-
const
|
|
36106
|
-
if (!
|
|
37152
|
+
const stat2 = fs12.lstatSync(filePath);
|
|
37153
|
+
if (!stat2.isFile())
|
|
36107
37154
|
throw new Error("unsafe daemon replacement lock type");
|
|
36108
37155
|
fs12.chmodSync(filePath, 384);
|
|
36109
37156
|
const content = JSON.parse(fs12.readFileSync(filePath, "utf8"));
|
|
@@ -36166,7 +37213,7 @@ function checkReplacementLock(baseDir, machineId, resumeRequestId) {
|
|
|
36166
37213
|
}
|
|
36167
37214
|
function acquireDaemonReplacementLock(args) {
|
|
36168
37215
|
const lockPath = replacementLockPathById(args.baseDir, args.machineId);
|
|
36169
|
-
ensurePrivateDir2(
|
|
37216
|
+
ensurePrivateDir2(path17.dirname(lockPath));
|
|
36170
37217
|
checkReplacementLock(args.baseDir, args.machineId);
|
|
36171
37218
|
const lock = {
|
|
36172
37219
|
pid: process.pid,
|
|
@@ -36179,11 +37226,11 @@ function acquireDaemonReplacementLock(args) {
|
|
|
36179
37226
|
return { path: lockPath, lock };
|
|
36180
37227
|
}
|
|
36181
37228
|
function coarseStartLockPath(baseDir) {
|
|
36182
|
-
return
|
|
37229
|
+
return path17.join(daemonsDir(baseDir), ".start.lock");
|
|
36183
37230
|
}
|
|
36184
37231
|
function acquireCoarseLock(baseDir, ownerToken) {
|
|
36185
37232
|
const lf = coarseStartLockPath(baseDir);
|
|
36186
|
-
ensurePrivateDir2(
|
|
37233
|
+
ensurePrivateDir2(path17.dirname(lf));
|
|
36187
37234
|
secureExistingFile(lf);
|
|
36188
37235
|
clearStaleOwnership(lf, (pid) => new Error(`another daemon start is in progress on this machine (pid ${pid})`));
|
|
36189
37236
|
writeExclusive(lf, { pid: process.pid, machineId: "coarse", startedAt: new Date().toISOString(), ownerToken });
|
|
@@ -36192,7 +37239,7 @@ function acquireCoarseLock(baseDir, ownerToken) {
|
|
|
36192
37239
|
function acquireLaunchLock(baseDir, machineId, ownerToken, resumeRequestId) {
|
|
36193
37240
|
const daemonDir = daemonDirById(baseDir, machineId);
|
|
36194
37241
|
ensurePrivateDir2(daemonDir);
|
|
36195
|
-
const lockPath =
|
|
37242
|
+
const lockPath = path17.join(daemonDir, "daemon.launch.lock");
|
|
36196
37243
|
const finalPath = pidfilePathById(baseDir, machineId);
|
|
36197
37244
|
checkReplacementLock(baseDir, machineId, resumeRequestId);
|
|
36198
37245
|
secureExistingFile(lockPath);
|
|
@@ -36214,9 +37261,9 @@ function legacyPidfileCandidates(baseDir) {
|
|
|
36214
37261
|
const candidates = [];
|
|
36215
37262
|
for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
|
|
36216
37263
|
if (entry.isDirectory()) {
|
|
36217
|
-
candidates.push(
|
|
37264
|
+
candidates.push(path17.join(dir, entry.name, "daemon.pid"));
|
|
36218
37265
|
} else if (entry.isFile() && entry.name.endsWith(".pid")) {
|
|
36219
|
-
candidates.push(
|
|
37266
|
+
candidates.push(path17.join(dir, entry.name));
|
|
36220
37267
|
}
|
|
36221
37268
|
}
|
|
36222
37269
|
return candidates;
|
|
@@ -36288,7 +37335,7 @@ function daemonList(opts) {
|
|
|
36288
37335
|
for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
|
|
36289
37336
|
if (entry.isDirectory() && isDaemonId(entry.name)) {
|
|
36290
37337
|
const id = entry.name;
|
|
36291
|
-
pushRow(id,
|
|
37338
|
+
pushRow(id, path17.join(dir, id, "daemon.pid"), path17.join(dir, id, "status.json"));
|
|
36292
37339
|
}
|
|
36293
37340
|
}
|
|
36294
37341
|
return results;
|
|
@@ -36336,7 +37383,7 @@ function daemonIdsWithStatus(baseDir) {
|
|
|
36336
37383
|
return [];
|
|
36337
37384
|
const ids = [];
|
|
36338
37385
|
for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
|
|
36339
|
-
if (entry.isDirectory() && isDaemonId(entry.name) && fs12.existsSync(
|
|
37386
|
+
if (entry.isDirectory() && isDaemonId(entry.name) && fs12.existsSync(path17.join(dir, entry.name, "status.json"))) {
|
|
36340
37387
|
ids.push(entry.name);
|
|
36341
37388
|
}
|
|
36342
37389
|
}
|
|
@@ -36399,16 +37446,16 @@ async function stopByPidfile(pf, notFoundHint) {
|
|
|
36399
37446
|
}
|
|
36400
37447
|
async function daemonStop(opts) {
|
|
36401
37448
|
const baseDir = opts.baseDir || process.env.ALOOK_DATA_DIR || DEFAULT_BASE_DIR;
|
|
36402
|
-
await stopByPidfile(
|
|
37449
|
+
await stopByPidfile(path17.join(daemonDirById(baseDir, opts.id), "daemon.pid"), `no daemon with id '${opts.id}' (pidfile not found — check \`alook daemon list\`)`);
|
|
36403
37450
|
}
|
|
36404
37451
|
function credentialFilePathByMachineId(baseDir, machineId) {
|
|
36405
|
-
return
|
|
37452
|
+
return path17.join(daemonsDir(baseDir), `${validateMachineId(machineId)}.credential.json`);
|
|
36406
37453
|
}
|
|
36407
37454
|
function readCredentialFile(filePath) {
|
|
36408
37455
|
if (!fs12.existsSync(filePath))
|
|
36409
37456
|
return null;
|
|
36410
|
-
const
|
|
36411
|
-
if (!
|
|
37457
|
+
const stat2 = fs12.lstatSync(filePath);
|
|
37458
|
+
if (!stat2.isFile())
|
|
36412
37459
|
throw new Error("unsafe daemon credential file type");
|
|
36413
37460
|
fs12.chmodSync(filePath, 384);
|
|
36414
37461
|
try {
|
|
@@ -36449,7 +37496,7 @@ function findExistingCredentialForBearer(baseDir, bearer) {
|
|
|
36449
37496
|
for (const file2 of fs12.readdirSync(dir)) {
|
|
36450
37497
|
if (!file2.endsWith(".credential.json"))
|
|
36451
37498
|
continue;
|
|
36452
|
-
const parsed = readCredentialFile(
|
|
37499
|
+
const parsed = readCredentialFile(path17.join(dir, file2));
|
|
36453
37500
|
if (parsed && parsed.credential === bearer)
|
|
36454
37501
|
return parsed;
|
|
36455
37502
|
}
|
|
@@ -36730,7 +37777,7 @@ function waitForReceipt(child, prepared) {
|
|
|
36730
37777
|
};
|
|
36731
37778
|
const configuredTestTimeout = NaN;
|
|
36732
37779
|
const receiptTimeoutMs = Number.isFinite(configuredTestTimeout) && configuredTestTimeout > 0 ? configuredTestTimeout : START_RECEIPT_TIMEOUT_MS;
|
|
36733
|
-
const timeout = setTimeout(() => settle(new Error(`daemon start timed out; inspect ${
|
|
37780
|
+
const timeout = setTimeout(() => settle(new Error(`daemon start timed out; inspect ${path17.join(prepared.daemonDir, "daemon.log")}`)), receiptTimeoutMs);
|
|
36734
37781
|
child.on("message", (message2) => {
|
|
36735
37782
|
const accepted = message2;
|
|
36736
37783
|
if (accepted.type === "daemon:accepted") {
|
|
@@ -36749,7 +37796,7 @@ function waitForReceipt(child, prepared) {
|
|
|
36749
37796
|
settle(undefined, receipt);
|
|
36750
37797
|
});
|
|
36751
37798
|
child.once("exit", (code, signal) => {
|
|
36752
|
-
settle(new Error(`daemon child exited before ready (${signal ?? code}); inspect ${
|
|
37799
|
+
settle(new Error(`daemon child exited before ready (${signal ?? code}); inspect ${path17.join(prepared.daemonDir, "daemon.log")}`));
|
|
36753
37800
|
});
|
|
36754
37801
|
child.once("error", (error51) => settle(error51));
|
|
36755
37802
|
});
|
|
@@ -37116,6 +38163,7 @@ function stripMalformedAlookHeredocTail(input) {
|
|
|
37116
38163
|
}
|
|
37117
38164
|
var CLIENT_MAX_ATTACHMENT_BYTES = 26214400;
|
|
37118
38165
|
var CLIENT_MAX_MESSAGE_BODY_BYTES = 1024;
|
|
38166
|
+
var INBOX_PULL_OUTPUT_DEADLINE_MS = 9000;
|
|
37119
38167
|
function contentTypeFromFilename(filename) {
|
|
37120
38168
|
const ext = filename.slice(filename.lastIndexOf(".") + 1).toLowerCase();
|
|
37121
38169
|
switch (ext) {
|
|
@@ -37415,11 +38463,14 @@ async function cmdInboxPull(opts) {
|
|
|
37415
38463
|
const api2 = getApi();
|
|
37416
38464
|
const agent2 = agentId(opts);
|
|
37417
38465
|
const max = opts.max ? Number(opts.max) : undefined;
|
|
38466
|
+
const pullStartedAt = performance.now();
|
|
37418
38467
|
const { messages, hasMore, markedCount } = await api2.inboxPull({ agentId: agent2, max });
|
|
38468
|
+
const pullElapsedMs = performance.now() - pullStartedAt;
|
|
37419
38469
|
const pulledAt = nowLocalISO();
|
|
37420
38470
|
let acked = 0;
|
|
37421
38471
|
let ackError;
|
|
37422
38472
|
let failed;
|
|
38473
|
+
let ackDeferred;
|
|
37423
38474
|
if (messages.length > 0) {
|
|
37424
38475
|
const latest = new Map;
|
|
37425
38476
|
for (const m of messages) {
|
|
@@ -37428,12 +38479,20 @@ async function cmdInboxPull(opts) {
|
|
|
37428
38479
|
if (!cur || seqN > cur.seq)
|
|
37429
38480
|
latest.set(m.channel, { channel: m.channel, seq: seqN });
|
|
37430
38481
|
}
|
|
37431
|
-
|
|
37432
|
-
|
|
37433
|
-
|
|
37434
|
-
|
|
37435
|
-
|
|
37436
|
-
|
|
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
|
+
}
|
|
37437
38496
|
}
|
|
37438
38497
|
}
|
|
37439
38498
|
return {
|
|
@@ -37443,6 +38502,7 @@ async function cmdInboxPull(opts) {
|
|
|
37443
38502
|
pulledAt,
|
|
37444
38503
|
...failed ? { failed } : {},
|
|
37445
38504
|
...ackError ? { ackError } : {},
|
|
38505
|
+
...ackDeferred ? { ackDeferred } : {},
|
|
37446
38506
|
...markedCount > 0 ? {
|
|
37447
38507
|
markedReminder: `You have ${markedCount} marked ${markedCount === 1 ? "message" : "messages"}. Resolve ${markedCount === 1 ? "it" : "them"} before going dark unless blocked.`
|
|
37448
38508
|
} : {}
|