@aku11i/phantom 6.3.0-2 → 6.3.0-4

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.
@@ -3708,6 +3708,97 @@ function handleIntersectionResults(result, left, right) {
3708
3708
  result.value = merged.data;
3709
3709
  return result;
3710
3710
  }
3711
+ const $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
3712
+ $ZodType.init(inst, def);
3713
+ inst._zod.parse = (payload, ctx) => {
3714
+ const input = payload.value;
3715
+ if (!isPlainObject$2(input)) {
3716
+ payload.issues.push({
3717
+ expected: "record",
3718
+ code: "invalid_type",
3719
+ input,
3720
+ inst
3721
+ });
3722
+ return payload;
3723
+ }
3724
+ const proms = [];
3725
+ const values = def.keyType._zod.values;
3726
+ if (values) {
3727
+ payload.value = {};
3728
+ const recordKeys = /* @__PURE__ */ new Set();
3729
+ for (const key of values) if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") {
3730
+ recordKeys.add(typeof key === "number" ? key.toString() : key);
3731
+ const result = def.valueType._zod.run({
3732
+ value: input[key],
3733
+ issues: []
3734
+ }, ctx);
3735
+ if (result instanceof Promise) proms.push(result.then((result) => {
3736
+ if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
3737
+ payload.value[key] = result.value;
3738
+ }));
3739
+ else {
3740
+ if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
3741
+ payload.value[key] = result.value;
3742
+ }
3743
+ }
3744
+ let unrecognized;
3745
+ for (const key in input) if (!recordKeys.has(key)) {
3746
+ unrecognized = unrecognized ?? [];
3747
+ unrecognized.push(key);
3748
+ }
3749
+ if (unrecognized && unrecognized.length > 0) payload.issues.push({
3750
+ code: "unrecognized_keys",
3751
+ input,
3752
+ inst,
3753
+ keys: unrecognized
3754
+ });
3755
+ } else {
3756
+ payload.value = {};
3757
+ for (const key of Reflect.ownKeys(input)) {
3758
+ if (key === "__proto__") continue;
3759
+ let keyResult = def.keyType._zod.run({
3760
+ value: key,
3761
+ issues: []
3762
+ }, ctx);
3763
+ if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently");
3764
+ if (typeof key === "string" && number$2.test(key) && keyResult.issues.length) {
3765
+ const retryResult = def.keyType._zod.run({
3766
+ value: Number(key),
3767
+ issues: []
3768
+ }, ctx);
3769
+ if (retryResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently");
3770
+ if (retryResult.issues.length === 0) keyResult = retryResult;
3771
+ }
3772
+ if (keyResult.issues.length) {
3773
+ if (def.mode === "loose") payload.value[key] = input[key];
3774
+ else payload.issues.push({
3775
+ code: "invalid_key",
3776
+ origin: "record",
3777
+ issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())),
3778
+ input: key,
3779
+ path: [key],
3780
+ inst
3781
+ });
3782
+ continue;
3783
+ }
3784
+ const result = def.valueType._zod.run({
3785
+ value: input[key],
3786
+ issues: []
3787
+ }, ctx);
3788
+ if (result instanceof Promise) proms.push(result.then((result) => {
3789
+ if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
3790
+ payload.value[keyResult.value] = result.value;
3791
+ }));
3792
+ else {
3793
+ if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
3794
+ payload.value[keyResult.value] = result.value;
3795
+ }
3796
+ }
3797
+ }
3798
+ if (proms.length) return Promise.all(proms).then(() => payload);
3799
+ return payload;
3800
+ };
3801
+ });
3711
3802
  const $ZodEnum = /* @__PURE__ */ $constructor("$ZodEnum", (inst, def) => {
3712
3803
  $ZodType.init(inst, def);
3713
3804
  const values = getEnumValues(def.entries);
@@ -4978,6 +5069,39 @@ const intersectionProcessor = (schema, ctx, json, params) => {
4978
5069
  const isSimpleIntersection = (val) => "allOf" in val && Object.keys(val).length === 1;
4979
5070
  json.allOf = [...isSimpleIntersection(a) ? a.allOf : [a], ...isSimpleIntersection(b) ? b.allOf : [b]];
4980
5071
  };
5072
+ const recordProcessor = (schema, ctx, _json, params) => {
5073
+ const json = _json;
5074
+ const def = schema._zod.def;
5075
+ json.type = "object";
5076
+ const keyType = def.keyType;
5077
+ const patterns = keyType._zod.bag?.patterns;
5078
+ if (def.mode === "loose" && patterns && patterns.size > 0) {
5079
+ const valueSchema = process$1(def.valueType, ctx, {
5080
+ ...params,
5081
+ path: [
5082
+ ...params.path,
5083
+ "patternProperties",
5084
+ "*"
5085
+ ]
5086
+ });
5087
+ json.patternProperties = {};
5088
+ for (const pattern of patterns) json.patternProperties[pattern.source] = valueSchema;
5089
+ } else {
5090
+ if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") json.propertyNames = process$1(def.keyType, ctx, {
5091
+ ...params,
5092
+ path: [...params.path, "propertyNames"]
5093
+ });
5094
+ json.additionalProperties = process$1(def.valueType, ctx, {
5095
+ ...params,
5096
+ path: [...params.path, "additionalProperties"]
5097
+ });
5098
+ }
5099
+ const keyValues = keyType._zod.values;
5100
+ if (keyValues) {
5101
+ const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number");
5102
+ if (validKeyValues.length > 0) json.required = validKeyValues;
5103
+ }
5104
+ };
4981
5105
  const nullableProcessor = (schema, ctx, json, params) => {
4982
5106
  const def = schema._zod.def;
4983
5107
  const inner = process$1(def.innerType, ctx, params);
@@ -5470,6 +5594,21 @@ function intersection(left, right) {
5470
5594
  right
5471
5595
  });
5472
5596
  }
5597
+ const ZodRecord = /* @__PURE__ */ $constructor("ZodRecord", (inst, def) => {
5598
+ $ZodRecord.init(inst, def);
5599
+ ZodType.init(inst, def);
5600
+ inst._zod.processJSONSchema = (ctx, json, params) => recordProcessor(inst, ctx, json, params);
5601
+ inst.keyType = def.keyType;
5602
+ inst.valueType = def.valueType;
5603
+ });
5604
+ function record(keyType, valueType, params) {
5605
+ return new ZodRecord({
5606
+ type: "record",
5607
+ keyType,
5608
+ valueType,
5609
+ ...normalizeParams(params)
5610
+ });
5611
+ }
5473
5612
  const ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
5474
5613
  $ZodEnum.init(inst, def);
5475
5614
  ZodType.init(inst, def);
@@ -23446,22 +23585,40 @@ async function createGitHubClient() {
23446
23585
  //#endregion
23447
23586
  //#region ../github/src/api/checkout-target.ts
23448
23587
  async function listGitHubCheckoutTargets$1(owner, repo, options = {}) {
23449
- const { data } = await (await createGitHubClient()).issues.listForRepo({
23588
+ const github = await createGitHubClient();
23589
+ const perPage = options.limit ?? 30;
23590
+ const [{ data: issues }, { data: pullRequests }] = await Promise.all([github.issues.listForRepo({
23450
23591
  owner,
23451
23592
  repo,
23452
23593
  state: "open",
23453
23594
  sort: "updated",
23454
23595
  direction: "desc",
23455
- per_page: options.limit ?? 30
23596
+ per_page: perPage
23597
+ }), github.pulls.list({
23598
+ owner,
23599
+ repo,
23600
+ state: "open",
23601
+ sort: "updated",
23602
+ direction: "desc",
23603
+ per_page: perPage
23604
+ }).catch(() => ({ data: [] }))]);
23605
+ const pullRequestByNumber = new Map(pullRequests.map((pullRequest) => [pullRequest.number, pullRequest]));
23606
+ return issues.map((item) => {
23607
+ const pullRequest = item.pull_request ? pullRequestByNumber.get(item.number) : void 0;
23608
+ return {
23609
+ author: item.user?.login ?? null,
23610
+ ...pullRequest ? {
23611
+ baseRepoFullName: pullRequest.base.repo.full_name,
23612
+ headRef: pullRequest.head.ref,
23613
+ headRepoFullName: pullRequest.head.repo?.full_name
23614
+ } : {},
23615
+ htmlUrl: item.html_url,
23616
+ kind: item.pull_request ? "pullRequest" : "issue",
23617
+ number: item.number,
23618
+ title: item.title,
23619
+ updatedAt: item.updated_at
23620
+ };
23456
23621
  });
23457
- return data.map((item) => ({
23458
- author: item.user?.login ?? null,
23459
- htmlUrl: item.html_url,
23460
- kind: item.pull_request ? "pullRequest" : "issue",
23461
- number: item.number,
23462
- title: item.title,
23463
- updatedAt: item.updated_at
23464
- }));
23465
23622
  }
23466
23623
  //#endregion
23467
23624
  //#region ../github/src/api/pull-request.ts
@@ -25308,6 +25465,19 @@ function summarizeCodexEvent(method, params) {
25308
25465
  }
25309
25466
  return method;
25310
25467
  }
25468
+ function rememberRecentProjectSkillSelection(recordsByProject, projectId, skillPath, lastUsedAt = (/* @__PURE__ */ new Date()).toISOString(), limit = 5) {
25469
+ const nextProjectRecords = [{
25470
+ path: skillPath,
25471
+ lastUsedAt
25472
+ }, ...(recordsByProject[projectId] ?? []).filter((record) => record.path !== skillPath)].sort((left, right) => right.lastUsedAt.localeCompare(left.lastUsedAt)).slice(0, Math.max(0, limit));
25473
+ return {
25474
+ ...recordsByProject,
25475
+ [projectId]: nextProjectRecords
25476
+ };
25477
+ }
25478
+ function getRecentProjectSkillRecords(recordsByProject, projectId) {
25479
+ return recordsByProject[projectId] ?? [];
25480
+ }
25311
25481
  //#endregion
25312
25482
  //#region ../state/src/types.ts
25313
25483
  const chatStatusSchema = _enum([
@@ -25351,6 +25521,11 @@ const turnContextItemBaseSchema = object({
25351
25521
  name: string(),
25352
25522
  path: string()
25353
25523
  });
25524
+ const recentProjectSkillRecordBaseSchema = object({
25525
+ path: string(),
25526
+ lastUsedAt: string()
25527
+ });
25528
+ const recentProjectSkillsByProjectBaseSchema = record(string(), array(recentProjectSkillRecordBaseSchema)).default({});
25354
25529
  const queuedMessageRecordBaseSchema = object({
25355
25530
  id: string(),
25356
25531
  chatId: string(),
@@ -25386,12 +25561,14 @@ object({
25386
25561
  chats: array(chatRecordBaseSchema),
25387
25562
  messages: array(chatMessageRecordBaseSchema),
25388
25563
  queuedMessages: array(queuedMessageRecordBaseSchema).default([]),
25564
+ recentProjectSkills: recentProjectSkillsByProjectBaseSchema,
25389
25565
  selectedProjectId: nullableStringFromUnknownSchema,
25390
25566
  selectedChatId: nullableStringFromUnknownSchema
25391
25567
  });
25392
25568
  const projectRecordSchema = projectRecordBaseSchema.passthrough();
25393
25569
  const chatMessageRecordSchema = chatMessageRecordBaseSchema.passthrough();
25394
25570
  const queuedMessageRecordSchema = queuedMessageRecordBaseSchema.passthrough();
25571
+ const recentProjectSkillRecordSchema = recentProjectSkillRecordBaseSchema.passthrough();
25395
25572
  const chatRecordSchema = chatRecordBaseSchema.passthrough();
25396
25573
  const serveStateSchema = object({
25397
25574
  version: literal(1),
@@ -25399,6 +25576,7 @@ const serveStateSchema = object({
25399
25576
  chats: array(chatRecordSchema),
25400
25577
  messages: array(chatMessageRecordSchema),
25401
25578
  queuedMessages: array(queuedMessageRecordSchema).default([]),
25579
+ recentProjectSkills: record(string(), array(recentProjectSkillRecordSchema)).default({}),
25402
25580
  selectedProjectId: nullableStringFromUnknownSchema,
25403
25581
  selectedChatId: nullableStringFromUnknownSchema
25404
25582
  }).passthrough();
@@ -25415,6 +25593,7 @@ function createEmptyState() {
25415
25593
  chats: [],
25416
25594
  messages: [],
25417
25595
  queuedMessages: [],
25596
+ recentProjectSkills: {},
25418
25597
  selectedProjectId: null,
25419
25598
  selectedChatId: null
25420
25599
  };
@@ -25480,7 +25659,8 @@ var ServeStateStore = class {
25480
25659
  projects: [...state.projects],
25481
25660
  chats: [...state.chats],
25482
25661
  messages: [...state.messages],
25483
- queuedMessages: [...state.queuedMessages]
25662
+ queuedMessages: [...state.queuedMessages],
25663
+ recentProjectSkills: cloneRecentProjectSkills(state.recentProjectSkills)
25484
25664
  });
25485
25665
  await this.save(nextState);
25486
25666
  return nextState;
@@ -25489,6 +25669,9 @@ var ServeStateStore = class {
25489
25669
  return nextUpdate;
25490
25670
  }
25491
25671
  };
25672
+ function cloneRecentProjectSkills(recordsByProject) {
25673
+ return Object.fromEntries(Object.entries(recordsByProject).map(([projectId, records]) => [projectId, [...records]]));
25674
+ }
25492
25675
  function touchProject(project) {
25493
25676
  const timestamp = now();
25494
25677
  return {
@@ -25637,12 +25820,37 @@ var ServeServices = class {
25637
25820
  chats: state.chats.filter((chat) => chat.projectId !== projectId),
25638
25821
  messages: state.messages.filter((message) => !removedChatIds.has(message.chatId)),
25639
25822
  queuedMessages: state.queuedMessages.filter((message) => !removedChatIds.has(message.chatId)),
25823
+ recentProjectSkills: Object.fromEntries(Object.entries(state.recentProjectSkills).filter(([storedProjectId]) => storedProjectId !== projectId)),
25640
25824
  selectedProjectId: state.selectedProjectId === projectId ? null : state.selectedProjectId,
25641
25825
  selectedChatId: removedChatIds.has(state.selectedChatId ?? "") ? null : state.selectedChatId
25642
25826
  };
25643
25827
  });
25644
25828
  this.eventHub.emit("project.removed", { projectId });
25645
25829
  }
25830
+ async listRecentProjectSkills(projectId) {
25831
+ const state = await this.store.load();
25832
+ const project = this.requireProject(state, projectId);
25833
+ return normalizeRecentProjectSkillRecordPaths(getRecentProjectSkillRecords(state.recentProjectSkills, projectId), getProjectSkillRoots(state, project));
25834
+ }
25835
+ async rememberRecentProjectSkill(projectId, skillPath) {
25836
+ if (!skillPath.trim()) throw new Error("Skill path is required");
25837
+ let recentSkills = [];
25838
+ const lastUsedAt = createTimestamp();
25839
+ await this.store.update((state) => {
25840
+ const projectSkillRoots = getProjectSkillRoots(state, this.requireProject(state, projectId));
25841
+ const normalizedSkillPath = normalizeProjectSkillPath(skillPath, projectSkillRoots);
25842
+ const recentProjectSkills = rememberRecentProjectSkillSelection({
25843
+ ...state.recentProjectSkills,
25844
+ [projectId]: normalizeRecentProjectSkillRecordPaths(getRecentProjectSkillRecords(state.recentProjectSkills, projectId), projectSkillRoots)
25845
+ }, projectId, normalizedSkillPath, lastUsedAt);
25846
+ recentSkills = getRecentProjectSkillRecords(recentProjectSkills, projectId);
25847
+ return {
25848
+ ...state,
25849
+ recentProjectSkills
25850
+ };
25851
+ });
25852
+ return recentSkills;
25853
+ }
25646
25854
  async listChats(projectId) {
25647
25855
  await this.resetStaleTransientChatState();
25648
25856
  const state = await this.store.load();
@@ -26054,9 +26262,12 @@ var ServeServices = class {
26054
26262
  const activeTurnId = chat.activeTurnId ?? (resetChatIds.has(chatId) ? null : findLocalSteeredTurnId(localMessages));
26055
26263
  if (!chat.codexThreadId) return localMessagesWithoutStaleSteeredState(chat, localMessages);
26056
26264
  try {
26057
- const codexMessages = normalizeCodexThreadMessages(await this.codex.readThread(chat.codexThreadId, { includeTurns: true }), chat.id);
26058
- if (codexMessages.length === 0) return localMessagesWithoutStaleSteeredState(chat, localMessages);
26059
- return mergeCodexAndLocalMessages(codexMessages, localMessages, activeTurnId, chat.activeTurnId != null);
26265
+ return resolveChatMessageTimeline({
26266
+ activeTurnId,
26267
+ chat,
26268
+ codexMessages: normalizeCodexThreadMessages(await this.codex.readThread(chat.codexThreadId, { includeTurns: true }), chat.id),
26269
+ localMessages
26270
+ });
26060
26271
  } catch {
26061
26272
  return localMessagesWithoutStaleSteeredState(chat, localMessages);
26062
26273
  }
@@ -26353,6 +26564,11 @@ var ServeServices = class {
26353
26564
  async listModels() {
26354
26565
  return normalizeModelRecords(await this.codex.listModels());
26355
26566
  }
26567
+ async listProjectSkills(projectId) {
26568
+ const state = await this.store.load();
26569
+ const project = this.requireProject(state, projectId);
26570
+ return normalizeSkillRecords(await this.codex.listSkills([project.rootPath]));
26571
+ }
26356
26572
  async listSkills(chatId) {
26357
26573
  const chat = await this.getChat(chatId);
26358
26574
  return normalizeSkillRecords(await this.codex.listSkills([chat.worktreePath]));
@@ -26366,7 +26582,7 @@ var ServeServices = class {
26366
26582
  async createCodexTurnOptions(input, chat) {
26367
26583
  const attachments = await this.normalizeAttachmentItems(input.attachments, chat.id);
26368
26584
  const files = await normalizeFileContextItems(input.files, chat.worktreePath);
26369
- const skills = await this.normalizeSkillContextItems(input.skills, chat.worktreePath);
26585
+ const skills = await this.normalizeSkillContextItems(input.skills, chat);
26370
26586
  if (!input.effort && !input.model && !input.serviceTier && attachments.length === 0 && files.length === 0 && skills.length === 0) return;
26371
26587
  const options = {};
26372
26588
  if (attachments.length > 0) options.attachments = attachments;
@@ -26410,13 +26626,22 @@ var ServeServices = class {
26410
26626
  };
26411
26627
  }));
26412
26628
  }
26413
- async normalizeSkillContextItems(items, worktreePath) {
26629
+ async normalizeSkillContextItems(items, chat) {
26414
26630
  const normalized = normalizeTurnContextItems(items);
26415
26631
  if (normalized.length === 0) return [];
26416
- const availableSkills = normalizeSkillRecords(await this.codex.listSkills([worktreePath]));
26417
- const skillsByPath = new Map(availableSkills.filter((skill) => skill.enabled).map((skill) => [skill.path, skill]));
26632
+ const state = await this.store.load();
26633
+ const project = this.requireProject(state, chat.projectId);
26634
+ const projectSkillRoots = getProjectSkillRoots(state, project);
26635
+ const skillListRoots = getSkillListRoots(chat, project);
26636
+ const availableSkills = normalizeSkillRecords(await this.codex.listSkills(skillListRoots));
26637
+ const skillsByPath = /* @__PURE__ */ new Map();
26638
+ for (const skill of sortSkillsByRootPreference(availableSkills.filter((candidate) => candidate.enabled), skillListRoots)) {
26639
+ skillsByPath.set(skill.path, skill);
26640
+ const skillIdentity = normalizeProjectSkillPath(skill.path, projectSkillRoots);
26641
+ if (!skillsByPath.has(skillIdentity)) skillsByPath.set(skillIdentity, skill);
26642
+ }
26418
26643
  return normalized.map((item) => {
26419
- const skill = skillsByPath.get(item.path);
26644
+ const skill = skillsByPath.get(normalizeProjectSkillPath(item.path, projectSkillRoots)) ?? skillsByPath.get(item.path);
26420
26645
  if (!skill) throw new Error(`Skill context path is not available: ${item.path}`);
26421
26646
  return {
26422
26647
  name: skill.name,
@@ -27055,6 +27280,7 @@ var ServeServices = class {
27055
27280
  return;
27056
27281
  }
27057
27282
  if (method === "warning" || method === "guardianWarning" || method === "configWarning") {
27283
+ if (isHiddenCodexWarning(method, params)) return;
27058
27284
  await this.addRichEventMessage({
27059
27285
  chatId,
27060
27286
  eventData: params,
@@ -27465,17 +27691,26 @@ function extractCodexText(value) {
27465
27691
  if (directText) return directText;
27466
27692
  return extractCodexText(value.content);
27467
27693
  }
27468
- function mergeCodexAndLocalMessages(codexMessages, localMessages, activeTurnId, protectActiveLocalTurn) {
27694
+ function resolveChatMessageTimeline({ activeTurnId, chat, codexMessages, localMessages }) {
27695
+ if (codexMessages.length === 0) return localMessagesWithoutStaleSteeredState(chat, localMessages);
27696
+ const localMessagesForCanonicalTranscript = isChatInActiveTurn(chat) ? localMessages : localMessagesWithoutStaleSteeredState(chat, localMessages);
27697
+ const canonicalLocalTranscriptMatch = isChatInActiveTurn(chat) ? emptyCanonicalLocalTranscriptMatch() : findCanonicalLocalTranscriptMatch(codexMessages, localMessagesForCanonicalTranscript);
27698
+ const deduplicatedCodexMessages = codexMessagesWithoutCanonicalLocalTranscript(codexMessages, canonicalLocalTranscriptMatch.codexMessageIndexes);
27699
+ if (deduplicatedCodexMessages.length === 0) return localMessagesWithoutStaleSteeredState(chat, localMessages);
27700
+ return mergeCodexAndLocalMessages(deduplicatedCodexMessages, localMessagesWithCanonicalStaleSteeredStateCleared(chat, localMessages, canonicalLocalTranscriptMatch), activeTurnId, chat.activeTurnId != null, canonicalLocalTranscriptMatch.localMessageCodexOrderMatches);
27701
+ }
27702
+ function mergeCodexAndLocalMessages(codexMessages, localMessages, activeTurnId, protectActiveLocalTurn, protectedLocalMessageCodexOrderMatches = /* @__PURE__ */ new Map()) {
27469
27703
  if (codexMessages.length === 0) return localMessages;
27470
27704
  const mergedCodexMessages = [...codexMessages];
27471
27705
  const unmatchedCodexMessageIndexes = codexMessages.map((_, index) => index);
27472
- const localMessageCodexOrderMatches = /* @__PURE__ */ new Map();
27706
+ const localMessageCodexOrderMatches = new Map(protectedLocalMessageCodexOrderMatches);
27473
27707
  const steeredLocalMessageCounts = countSteeredLocalMessages(localMessages);
27474
27708
  const fallbackTranscriptLocalMessageMatches = findFallbackTranscriptLocalMessageMatches(mergedCodexMessages, localMessages, activeTurnId, protectActiveLocalTurn ? findActiveLocalTurnStartIndex(localMessages) : localMessages.length);
27475
27709
  const liveAssistantDeltaCodexOrderLimits = findLiveAssistantDeltaCodexOrderLimits(localMessages, mergedCodexMessages, steeredLocalMessageCounts, activeTurnId);
27476
27710
  return assignMergedMessageSortKeys(mergedCodexMessages, localMessages.filter((message) => {
27477
27711
  if (message.role === "event" || message.role === "error") return true;
27478
27712
  if (message.eventType === "chat.message.queued") return true;
27713
+ if (protectedLocalMessageCodexOrderMatches.has(message.id)) return true;
27479
27714
  const fallbackTranscriptCodexIndex = fallbackTranscriptLocalMessageMatches.get(message.id);
27480
27715
  if (fallbackTranscriptCodexIndex !== void 0 && unmatchedCodexMessageIndexes.includes(fallbackTranscriptCodexIndex)) {
27481
27716
  const fallbackCodexMessage = mergedCodexMessages[fallbackTranscriptCodexIndex];
@@ -27524,10 +27759,98 @@ function mergeLocalMessageMetadataIntoCodexMessage(codexMessage, localMessage) {
27524
27759
  }
27525
27760
  function localMessagesWithoutStaleSteeredState(chat, localMessages) {
27526
27761
  if (isChatInActiveTurn(chat)) return localMessages;
27527
- return localMessages.map((message) => message.eventType === "chat.message.steered" ? {
27762
+ return localMessages.map((message) => localMessageWithoutStaleSteeredState(chat, message));
27763
+ }
27764
+ function localMessagesWithCanonicalStaleSteeredStateCleared(chat, localMessages, canonicalLocalTranscriptMatch) {
27765
+ if (isChatInActiveTurn(chat) || canonicalLocalTranscriptMatch.localMessageCodexOrderMatches.size === 0) return localMessages;
27766
+ return localMessages.map((message) => canonicalLocalTranscriptMatch.localMessageCodexOrderMatches.has(message.id) ? localMessageWithoutStaleSteeredState(chat, message) : message);
27767
+ }
27768
+ function localMessageWithoutStaleSteeredState(chat, message) {
27769
+ if (isChatInActiveTurn(chat) || message.eventType !== "chat.message.steered") return message;
27770
+ return {
27528
27771
  ...message,
27529
27772
  eventType: void 0
27530
- } : message);
27773
+ };
27774
+ }
27775
+ function emptyCanonicalLocalTranscriptMatch() {
27776
+ return {
27777
+ codexMessageIndexes: /* @__PURE__ */ new Set(),
27778
+ localMessageCodexOrderMatches: /* @__PURE__ */ new Map()
27779
+ };
27780
+ }
27781
+ function codexMessagesWithoutCanonicalLocalTranscript(codexMessages, duplicateCodexMessageIndexes) {
27782
+ if (duplicateCodexMessageIndexes.size === 0) return codexMessages;
27783
+ return codexMessages.filter((_, index) => !duplicateCodexMessageIndexes.has(index));
27784
+ }
27785
+ function findCanonicalLocalTranscriptMatch(codexMessages, localMessages) {
27786
+ const matchedEntries = findCanonicalLocalTranscriptEntries(codexMessages, localMessages);
27787
+ if (matchedEntries.length === 0) return emptyCanonicalLocalTranscriptMatch();
27788
+ return {
27789
+ codexMessageIndexes: new Set(matchedEntries.map((entry) => entry.codexIndex)),
27790
+ localMessageCodexOrderMatches: new Map(matchedEntries.map((entry) => [entry.localId, entry.message.codexOrder ?? entry.codexIndex]))
27791
+ };
27792
+ }
27793
+ function findCanonicalLocalTranscriptEntries(codexMessages, localMessages) {
27794
+ const minimumCanonicalTranscriptLength = 4;
27795
+ const matchedCodexEntries = [];
27796
+ let nextLocalIndex = 0;
27797
+ for (const [codexIndex, codexMessage] of codexMessages.entries()) {
27798
+ if (!isTranscriptMessage(codexMessage)) continue;
27799
+ const matchedLocalIndex = findNextCanonicalLocalTranscriptIndex(localMessages, nextLocalIndex, codexMessage);
27800
+ if (matchedLocalIndex === -1) break;
27801
+ const matchedLocalMessage = localMessages[matchedLocalIndex];
27802
+ if (!matchedLocalMessage) break;
27803
+ matchedCodexEntries.push({
27804
+ codexIndex,
27805
+ localId: matchedLocalMessage.id,
27806
+ message: codexMessage
27807
+ });
27808
+ nextLocalIndex = matchedLocalIndex + 1;
27809
+ }
27810
+ const matchedMessages = matchedCodexEntries.map((entry) => entry.message);
27811
+ const hasNewerCodexTranscriptMessage = hasCodexTranscriptMessageAfterMatchedPrefix(codexMessages, matchedCodexEntries);
27812
+ const hasSubstantialCanonicalTranscript = matchedMessages.length >= minimumCanonicalTranscriptLength && matchedMessages.some((message) => message.role === "user") && matchedMessages.filter((message) => message.role === "assistant").length >= 2;
27813
+ const hasOpenUserBoundaryBeforeNewerCodexTranscript = hasNewerCodexTranscriptMessage && matchedMessages[0]?.role === "user" && matchedMessages.some((message) => message.role === "assistant") && matchedMessages[matchedMessages.length - 1]?.role === "user";
27814
+ const hasCompletedExchangeBeforeSameTurnCodexAssistant = matchedMessages[0]?.role === "user" && matchedMessages.some((message) => message.role === "assistant") && matchedMessages[matchedMessages.length - 1]?.role === "assistant" && hasSameTurnAssistantMessageAfterMatchedPrefix(codexMessages, matchedCodexEntries);
27815
+ if (!hasSubstantialCanonicalTranscript && !hasOpenUserBoundaryBeforeNewerCodexTranscript && !hasCompletedExchangeBeforeSameTurnCodexAssistant) return [];
27816
+ if (new Set(matchedMessages.map((message) => message.codexTurnId).filter(Boolean)).size > 1 && !hasOpenUserBoundaryBeforeNewerCodexTranscript) return [];
27817
+ return matchedCodexEntries;
27818
+ }
27819
+ function findNextCanonicalLocalTranscriptIndex(localMessages, startIndex, codexMessage) {
27820
+ for (let localIndex = startIndex; localIndex < localMessages.length; localIndex += 1) {
27821
+ const localMessage = localMessages[localIndex];
27822
+ if (!isTranscriptMessage(localMessage)) {
27823
+ if (isSkippableCanonicalLocalTimelineMessage(localMessage)) continue;
27824
+ return -1;
27825
+ }
27826
+ return messageFingerprint(localMessage) === messageFingerprint(codexMessage) && isLocalMessageAtOrBeforeCodexMessage(localMessage, codexMessage) ? localIndex : -1;
27827
+ }
27828
+ return -1;
27829
+ }
27830
+ function isSkippableCanonicalLocalTimelineMessage(message) {
27831
+ return message.role === "event" || message.role === "error";
27832
+ }
27833
+ function hasCodexTranscriptMessageAfterMatchedPrefix(codexMessages, matchedEntries) {
27834
+ const lastMatchedEntry = matchedEntries[matchedEntries.length - 1];
27835
+ if (!lastMatchedEntry) return false;
27836
+ return codexMessages.some((message, index) => index > lastMatchedEntry.codexIndex && isTranscriptMessage(message));
27837
+ }
27838
+ function hasSameTurnAssistantMessageAfterMatchedPrefix(codexMessages, matchedEntries) {
27839
+ const lastMatchedEntry = matchedEntries[matchedEntries.length - 1];
27840
+ if (!lastMatchedEntry) return false;
27841
+ const lastMatchedMessage = codexMessages[lastMatchedEntry.codexIndex];
27842
+ if (!lastMatchedMessage?.codexTurnId) return false;
27843
+ return codexMessages.some((message, index) => index > lastMatchedEntry.codexIndex && message.codexTurnId === lastMatchedMessage.codexTurnId && message.role === "assistant" && isTranscriptMessage(message));
27844
+ }
27845
+ function isTranscriptMessage(message) {
27846
+ return (message.role === "assistant" || message.role === "user") && !isQueuedMessage(message) && !isPendingSteeredMessage(message);
27847
+ }
27848
+ function isLocalMessageAtOrBeforeCodexMessage(localMessage, codexMessage) {
27849
+ if (codexMessage.hasFallbackTimestamp) return true;
27850
+ const codexTime = Date.parse(codexMessage.createdAt);
27851
+ const localTime = Date.parse(localMessage.createdAt);
27852
+ if (Number.isFinite(codexTime) && Number.isFinite(localTime)) return localTime <= codexTime;
27853
+ return localMessage.createdAt <= codexMessage.createdAt;
27531
27854
  }
27532
27855
  function insertRecordAtIndex(records, record, index) {
27533
27856
  if (index >= records.length) return [...records, record];
@@ -27554,12 +27877,22 @@ function assignMergedMessageSortKeys(codexMessages, localMessages, allLocalMessa
27554
27877
  })];
27555
27878
  }
27556
27879
  function getLocalMessageMergeSortBucket(message, index, localMessages, orderedCodexMessages, localMessageCodexOrderMatches, liveAssistantDeltaCodexOrderLimits, steeredLocalMessageCounts, activeTurnId) {
27557
- if (isPendingSteeredMessage(message)) return orderedCodexMessages.length * 2 + 2;
27558
- if (isQueuedMessage(message)) return orderedCodexMessages.length * 2 + 3;
27880
+ if (isPendingSteeredMessage(message)) return getAfterCodexMessagesMergeSortBucket(orderedCodexMessages, 2);
27881
+ if (isQueuedMessage(message)) return getAfterCodexMessagesMergeSortBucket(orderedCodexMessages, 3);
27882
+ const matchedCodexOrder = localMessageCodexOrderMatches.get(message.id);
27883
+ if (matchedCodexOrder !== void 0 && isTranscriptMessage(message)) return matchedCodexOrder * 2;
27559
27884
  if (isLocalTimelineEvent(message)) return getLocalTimelineEventMergeSortBucket(index, localMessages, orderedCodexMessages, localMessageCodexOrderMatches, liveAssistantDeltaCodexOrderLimits, steeredLocalMessageCounts, activeTurnId);
27560
27885
  if (isLiveAssistantDeltaMessage(message)) return getLiveAssistantDeltaMergeSortBucket(message, index, localMessages, orderedCodexMessages, localMessageCodexOrderMatches, liveAssistantDeltaCodexOrderLimits, steeredLocalMessageCounts, activeTurnId);
27561
27886
  return getStandardLocalMessageMergeSortBucket(message, orderedCodexMessages, index, localMessages, localMessageCodexOrderMatches);
27562
27887
  }
27888
+ function getAfterCodexMessagesMergeSortBucket(orderedCodexMessages, offset) {
27889
+ return (orderedCodexMessages.reduce((maxOrder, message, index) => Math.max(maxOrder, message.codexOrder ?? index), -1) + 1) * 2 + offset;
27890
+ }
27891
+ function getBeforeCodexMessageMergeSortBucket(orderedCodexMessages, insertionIndex) {
27892
+ const codexMessage = orderedCodexMessages[insertionIndex];
27893
+ if (!codexMessage) return getAfterCodexMessagesMergeSortBucket(orderedCodexMessages, 1);
27894
+ return (codexMessage.codexOrder ?? insertionIndex) * 2 - 1;
27895
+ }
27563
27896
  function getLocalTimelineEventMergeSortBucket(index, localMessages, orderedCodexMessages, localMessageCodexOrderMatches, liveAssistantDeltaCodexOrderLimits, steeredLocalMessageCounts, activeTurnId) {
27564
27897
  const earlierLocalBoundaryBucket = localMessages.slice(0, index).map((message, index) => ({
27565
27898
  index,
@@ -27575,7 +27908,7 @@ function getLocalTimelineEventMergeSortBucket(index, localMessages, orderedCodex
27575
27908
  return earlierLocalBoundaryBucket + .5;
27576
27909
  }
27577
27910
  if (earlierLocalBoundaryBucket !== void 0) return earlierLocalBoundaryBucket + .5;
27578
- if (laterLocalBoundaryBucket === void 0) return orderedCodexMessages.length * 2 + 1;
27911
+ if (laterLocalBoundaryBucket === void 0) return getAfterCodexMessagesMergeSortBucket(orderedCodexMessages, 1);
27579
27912
  return laterLocalBoundaryBucket - .5;
27580
27913
  }
27581
27914
  function getLocalTimelineEventBoundaryMergeSortBucket(message, index, localMessages, orderedCodexMessages, localMessageCodexOrderMatches, liveAssistantDeltaCodexOrderLimits, steeredLocalMessageCounts, activeTurnId) {
@@ -27584,8 +27917,8 @@ function getLocalTimelineEventBoundaryMergeSortBucket(message, index, localMessa
27584
27917
  const boundaryBucket = getLocalUserBoundaryMergeSortBucket(message, index, localMessages, orderedCodexMessages, localMessageCodexOrderMatches);
27585
27918
  if (boundaryBucket !== null) return boundaryBucket;
27586
27919
  }
27587
- if (isPendingSteeredMessage(message)) return orderedCodexMessages.length * 2 + 2;
27588
- if (isQueuedMessage(message)) return orderedCodexMessages.length * 2 + 3;
27920
+ if (isPendingSteeredMessage(message)) return getAfterCodexMessagesMergeSortBucket(orderedCodexMessages, 2);
27921
+ if (isQueuedMessage(message)) return getAfterCodexMessagesMergeSortBucket(orderedCodexMessages, 3);
27589
27922
  if (!isLiveAssistantDeltaMessage(message)) return null;
27590
27923
  return getMergedLiveAssistantDeltaMergeSortBucket(message, orderedCodexMessages, localMessageCodexOrderMatches) ?? getLiveAssistantDeltaMergeSortBucket(message, index, localMessages, orderedCodexMessages, localMessageCodexOrderMatches, liveAssistantDeltaCodexOrderLimits, steeredLocalMessageCounts, activeTurnId);
27591
27924
  }
@@ -27593,9 +27926,9 @@ function getStandardLocalMessageMergeSortBucket(message, orderedCodexMessages, i
27593
27926
  const insertionIndex = orderedCodexMessages.findIndex((codexMessage) => codexMessage.createdAt > message.createdAt);
27594
27927
  if (insertionIndex !== -1 && orderedCodexMessages[insertionIndex]?.hasFallbackTimestamp) {
27595
27928
  const nextTrustedInsertionIndex = orderedCodexMessages.findIndex((codexMessage, index) => index > insertionIndex && !codexMessage.hasFallbackTimestamp && codexMessage.createdAt > message.createdAt);
27596
- return applyEarlierLocalCodexBoundary(nextTrustedInsertionIndex === -1 ? orderedCodexMessages.length * 2 + 1 : nextTrustedInsertionIndex * 2 - 1, index, localMessages, localMessageCodexOrderMatches);
27929
+ return applyEarlierLocalCodexBoundary(nextTrustedInsertionIndex === -1 ? getAfterCodexMessagesMergeSortBucket(orderedCodexMessages, 1) : getBeforeCodexMessageMergeSortBucket(orderedCodexMessages, nextTrustedInsertionIndex), index, localMessages, localMessageCodexOrderMatches);
27597
27930
  }
27598
- return applyEarlierLocalCodexBoundary(insertionIndex === -1 ? orderedCodexMessages.length * 2 + 1 : insertionIndex * 2 - 1, index, localMessages, localMessageCodexOrderMatches);
27931
+ return applyEarlierLocalCodexBoundary(insertionIndex === -1 ? getAfterCodexMessagesMergeSortBucket(orderedCodexMessages, 1) : getBeforeCodexMessageMergeSortBucket(orderedCodexMessages, insertionIndex), index, localMessages, localMessageCodexOrderMatches);
27599
27932
  }
27600
27933
  function applyEarlierLocalCodexBoundary(bucket, index, localMessages, localMessageCodexOrderMatches) {
27601
27934
  if (index === void 0 || !localMessages || !localMessageCodexOrderMatches) return bucket;
@@ -27626,9 +27959,9 @@ function getLiveAssistantDeltaMergeSortBucket(message, index, localMessages, ord
27626
27959
  const boundaryInsertionIndex = findLiveAssistantDeltaBoundaryInsertionIndex(message, index, localMessages, orderedCodexMessages, liveAssistantDeltaCodexOrderLimits, steeredLocalMessageCounts, activeTurnId);
27627
27960
  if (boundaryInsertionIndex === null) {
27628
27961
  const earlierMatchedCodexOrder = getEarlierLocalCodexOrder(index, localMessages, localMessageCodexOrderMatches);
27629
- return earlierMatchedCodexOrder === void 0 ? orderedCodexMessages.length * 2 + 1 : earlierMatchedCodexOrder * 2 + .5;
27962
+ return earlierMatchedCodexOrder === void 0 ? getAfterCodexMessagesMergeSortBucket(orderedCodexMessages, 1) : earlierMatchedCodexOrder * 2 + .5;
27630
27963
  }
27631
- return applyEarlierLocalCodexBoundary(boundaryInsertionIndex * 2 - 1, index, localMessages, localMessageCodexOrderMatches);
27964
+ return applyEarlierLocalCodexBoundary(getBeforeCodexMessageMergeSortBucket(orderedCodexMessages, boundaryInsertionIndex), index, localMessages, localMessageCodexOrderMatches);
27632
27965
  }
27633
27966
  function findLiveAssistantDeltaBoundaryInsertionIndex(message, index, localMessages, orderedCodexMessages, liveAssistantDeltaCodexOrderLimits, steeredLocalMessageCounts, activeTurnId) {
27634
27967
  if (!isLiveAssistantDeltaMessage(message)) return null;
@@ -28184,6 +28517,40 @@ function normalizeSkillRecords(value) {
28184
28517
  };
28185
28518
  }).filter((skill) => Boolean(skill));
28186
28519
  }
28520
+ function getProjectSkillRoots(state, project) {
28521
+ return Array.from(new Set([project.rootPath, ...state.chats.filter((chat) => chat.projectId === project.id).map((chat) => chat.worktreePath)])).sort((left, right) => right.length - left.length);
28522
+ }
28523
+ function getSkillListRoots(chat, project) {
28524
+ return Array.from(new Set([chat.worktreePath, project.rootPath]));
28525
+ }
28526
+ function sortSkillsByRootPreference(skills, roots) {
28527
+ return [...skills].sort((left, right) => getPathRootIndex(left.path, roots) - getPathRootIndex(right.path, roots));
28528
+ }
28529
+ function getPathRootIndex(path, roots) {
28530
+ if (!isAbsolute(path)) return roots.length;
28531
+ const rootIndex = roots.findIndex((root) => isPathInside(root, path));
28532
+ return rootIndex === -1 ? roots.length : rootIndex;
28533
+ }
28534
+ function normalizeRecentProjectSkillRecordPaths(records, projectSkillRoots) {
28535
+ const seenSkillPaths = /* @__PURE__ */ new Set();
28536
+ return records.map((record) => ({
28537
+ ...record,
28538
+ path: normalizeProjectSkillPath(record.path, projectSkillRoots)
28539
+ })).filter((record) => {
28540
+ if (seenSkillPaths.has(record.path)) return false;
28541
+ seenSkillPaths.add(record.path);
28542
+ return true;
28543
+ });
28544
+ }
28545
+ function normalizeProjectSkillPath(skillPath, projectSkillRoots) {
28546
+ const trimmedSkillPath = skillPath.trim();
28547
+ if (!isAbsolute(trimmedSkillPath)) return trimmedSkillPath;
28548
+ for (const root of projectSkillRoots) {
28549
+ const relativeSkillPath = relative(root, trimmedSkillPath);
28550
+ if (relativeSkillPath && !relativeSkillPath.startsWith(`..${sep}`) && relativeSkillPath !== ".." && !isAbsolute(relativeSkillPath)) return relativeSkillPath.split(sep).join("/");
28551
+ }
28552
+ return trimmedSkillPath;
28553
+ }
28187
28554
  function normalizeFileRecords(value) {
28188
28555
  return (getRecordArray(value, "files") ?? []).map((file) => {
28189
28556
  const matchType = getRecordString(file, "match_type");
@@ -28345,6 +28712,16 @@ function sanitizeCodexEventParams(method, params) {
28345
28712
  }
28346
28713
  return params;
28347
28714
  }
28715
+ const hiddenCodexWarningMessages = new Set(["Automatic approval review approved"]);
28716
+ function isHiddenCodexWarning(method, params) {
28717
+ if (method !== "warning" && method !== "guardianWarning" && method !== "configWarning") return false;
28718
+ const object = getParamObject(params);
28719
+ return [
28720
+ summarizeCodexEvent(method, params),
28721
+ typeof object?.message === "string" ? object.message : null,
28722
+ typeof object?.summary === "string" ? object.summary : null
28723
+ ].some((candidate) => typeof candidate === "string" && hiddenCodexWarningMessages.has(candidate.trim()));
28724
+ }
28348
28725
  function sanitizeCodexEventItem(item) {
28349
28726
  const itemType = getRecordString(item, "type");
28350
28727
  if (itemType === "commandExecution") return stripRecordKey(item, "aggregatedOutput");
@@ -28548,6 +28925,7 @@ const deleteWorktreeSchema = worktreeSchema.extend({
28548
28925
  force: boolean().optional(),
28549
28926
  keepBranch: boolean().optional()
28550
28927
  });
28928
+ const recentProjectSkillSchema = object({ path: string().min(1, "Skill path is required") });
28551
28929
  const sendMessageSchema = object({
28552
28930
  text: string().min(1, "Message text is required"),
28553
28931
  attachments: array(attachmentSchema).optional(),
@@ -28734,6 +29112,28 @@ const rpcRoutes = new Hono().get("/health", async (c) => {
28734
29112
  } catch (error) {
28735
29113
  return handleApiError(c, error);
28736
29114
  }
29115
+ }).get("/projects/:projectId/skills", async (c) => {
29116
+ try {
29117
+ const skills = await getServeServices().listProjectSkills(c.req.param("projectId"));
29118
+ return c.json({ skills }, 200);
29119
+ } catch (error) {
29120
+ return handleApiError(c, error);
29121
+ }
29122
+ }).get("/projects/:projectId/recent-skills", async (c) => {
29123
+ try {
29124
+ const recentSkills = await getServeServices().listRecentProjectSkills(c.req.param("projectId"));
29125
+ return c.json({ recentSkills }, 200);
29126
+ } catch (error) {
29127
+ return handleApiError(c, error);
29128
+ }
29129
+ }).post("/projects/:projectId/recent-skills", jsonBody(recentProjectSkillSchema), async (c) => {
29130
+ try {
29131
+ const body = c.req.valid("json");
29132
+ const recentSkills = await getServeServices().rememberRecentProjectSkill(c.req.param("projectId"), body.path);
29133
+ return c.json({ recentSkills }, 200);
29134
+ } catch (error) {
29135
+ return handleApiError(c, error);
29136
+ }
28737
29137
  }).get("/projects/:projectId/github/checkout-targets", async (c) => {
28738
29138
  try {
28739
29139
  const github = await getServeServices().listProjectGitHubCheckoutTargets(c.req.param("projectId"));
@@ -29144,4 +29544,4 @@ function createApp() {
29144
29544
  //#endregion
29145
29545
  export { EventHub as a, getServeServices as i, rpcRoutes as n, createSseResponse as o, ServeServices as r, parseLastEventId as s, createApp as t };
29146
29546
 
29147
- //# sourceMappingURL=app-BLBOjh4e.mjs.map
29547
+ //# sourceMappingURL=app-DS_9Jsep.mjs.map