diff --git a/apps/stage-pocket/src/components/DataGui/DualEndRange.vue b/apps/stage-pocket/src/components/DataGui/DualEndRange.vue index 8466d1d27..741c0bc5e 100644 --- a/apps/stage-pocket/src/components/DataGui/DualEndRange.vue +++ b/apps/stage-pocket/src/components/DataGui/DualEndRange.vue @@ -73,7 +73,7 @@ const sortedValues = computed(() => { const sliderStyle = computed(() => { const sliderOffset = valueToPercent(sortedValues.value[0], props.min, props.max) - const sliderLeap = valueToPercent(sortedValues.value[sortedValues.value.length - 1], props.min, props.max) - sliderOffset + const sliderLeap = valueToPercent(sortedValues.value.at(-1), props.min, props.max) - sliderOffset return { left: `${sliderOffset}%`, width: `${sliderLeap}%`, diff --git a/apps/stage-pocket/src/pages/devtools/background-removal.vue b/apps/stage-pocket/src/pages/devtools/background-removal.vue index 2877391d0..66dbb3f14 100644 --- a/apps/stage-pocket/src/pages/devtools/background-removal.vue +++ b/apps/stage-pocket/src/pages/devtools/background-removal.vue @@ -170,7 +170,7 @@ function downloadAllImages() { doneItems.forEach((_, i) => { const index = imageItems.value.indexOf(doneItems[i]) - setTimeout(() => downloadImage(index), i * 100) + setTimeout(downloadImage, i * 100, index) }) } diff --git a/apps/stage-tamagotchi/src/main/windows/widgets/index.ts b/apps/stage-tamagotchi/src/main/windows/widgets/index.ts index 25ff283dc..c688df2a3 100644 --- a/apps/stage-tamagotchi/src/main/windows/widgets/index.ts +++ b/apps/stage-tamagotchi/src/main/windows/widgets/index.ts @@ -195,7 +195,7 @@ export function setupWidgetsWindowManager(params: { const record: WidgetRecord = { ...snapshot } if (snapshot.ttlMs > 0) { - record.timer = setTimeout(() => removeWidgetInternal(snapshot.id), snapshot.ttlMs) + record.timer = setTimeout(removeWidgetInternal, snapshot.ttlMs, snapshot.id) } widgetRecords.set(snapshot.id, record) diff --git a/apps/stage-tamagotchi/src/renderer/pages/widgets.vue b/apps/stage-tamagotchi/src/renderer/pages/widgets.vue index e42ae41b6..cab094644 100644 --- a/apps/stage-tamagotchi/src/renderer/pages/widgets.vue +++ b/apps/stage-tamagotchi/src/renderer/pages/widgets.vue @@ -65,7 +65,7 @@ function applySnapshot(snapshot: WidgetSnapshot) { } if (snapshot.ttlMs && snapshot.ttlMs > 0) { - ttlTimer = setTimeout(() => requestRemoval(snapshot.id), snapshot.ttlMs) + ttlTimer = setTimeout(requestRemoval, snapshot.ttlMs, snapshot.id) } } diff --git a/apps/stage-tamagotchi/src/renderer/widgets/map/components/Map.vue b/apps/stage-tamagotchi/src/renderer/widgets/map/components/Map.vue index b3652db24..473285f80 100644 --- a/apps/stage-tamagotchi/src/renderer/widgets/map/components/Map.vue +++ b/apps/stage-tamagotchi/src/renderer/widgets/map/components/Map.vue @@ -74,7 +74,7 @@ const routePoints = computed(() => { return [resolvedOrigin.value, resolvedDestination.value] const first = points[0] - const last = points[points.length - 1] + const last = points.at(-1) if (first.x !== resolvedOrigin.value.x || first.y !== resolvedOrigin.value.y) points.unshift(resolvedOrigin.value) if (last.x !== resolvedDestination.value.x || last.y !== resolvedDestination.value.y) diff --git a/apps/stage-web/src/components/DataGui/DualEndRange.vue b/apps/stage-web/src/components/DataGui/DualEndRange.vue index 8466d1d27..741c0bc5e 100644 --- a/apps/stage-web/src/components/DataGui/DualEndRange.vue +++ b/apps/stage-web/src/components/DataGui/DualEndRange.vue @@ -73,7 +73,7 @@ const sortedValues = computed(() => { const sliderStyle = computed(() => { const sliderOffset = valueToPercent(sortedValues.value[0], props.min, props.max) - const sliderLeap = valueToPercent(sortedValues.value[sortedValues.value.length - 1], props.min, props.max) - sliderOffset + const sliderLeap = valueToPercent(sortedValues.value.at(-1), props.min, props.max) - sliderOffset return { left: `${sliderOffset}%`, width: `${sliderLeap}%`, diff --git a/apps/stage-web/src/pages/devtools/background-removal.vue b/apps/stage-web/src/pages/devtools/background-removal.vue index 2877391d0..66dbb3f14 100644 --- a/apps/stage-web/src/pages/devtools/background-removal.vue +++ b/apps/stage-web/src/pages/devtools/background-removal.vue @@ -170,7 +170,7 @@ function downloadAllImages() { doneItems.forEach((_, i) => { const index = imageItems.value.indexOf(doneItems[i]) - setTimeout(() => downloadImage(index), i * 100) + setTimeout(downloadImage, i * 100, index) }) } diff --git a/apps/stage-web/src/stores/devtools-lag.ts b/apps/stage-web/src/stores/devtools-lag.ts index 8cda1733b..6acc5bc19 100644 --- a/apps/stage-web/src/stores/devtools-lag.ts +++ b/apps/stage-web/src/stores/devtools-lag.ts @@ -49,7 +49,7 @@ function calcStats(values: number[]) { const sorted = [...values].sort((a, b) => a - b) const idx = Math.max(0, Math.floor(0.95 * (sorted.length - 1))) const p95 = sorted[idx] - const latest = values[values.length - 1] + const latest = values.at(-1) return { avg, p95, latest } } @@ -134,7 +134,7 @@ export const useDevtoolsLagStore = defineStore('devtoolsLag', () => { recordingStartedAt.value = performance.now() resetRecordingSamples() - recordingTimeout = setTimeout(() => stopRecording(), 60000) + recordingTimeout = setTimeout(stopRecording, 60000) } function stopRecording(): RecordingSnapshot | undefined { diff --git a/docs/.vitepress/composables/outline.ts b/docs/.vitepress/composables/outline.ts index bab4c8f26..0ebb5c844 100644 --- a/docs/.vitepress/composables/outline.ts +++ b/docs/.vitepress/composables/outline.ts @@ -192,7 +192,7 @@ export function useActiveAnchor( // page bottom - highlight last link if (isBottom) { - activateLink(headers[headers.length - 1]!.link) + activateLink(headers.at(-1)!.link) return } diff --git a/docs/.vitepress/composables/sidebar.ts b/docs/.vitepress/composables/sidebar.ts index 5bb693bb0..230a04a0a 100644 --- a/docs/.vitepress/composables/sidebar.ts +++ b/docs/.vitepress/composables/sidebar.ts @@ -288,7 +288,7 @@ export function hasActiveLink( } function addBase(items: SidebarItem[], _base?: string): SidebarItem[] { - return [...items].map((_item) => { + return Array.from(items, (_item) => { const item = { ..._item } const base = item.base || _base if (base && item.link) diff --git a/docs/content/en/blog/DevLog-2025.08.01/CharacterMatcher.vue b/docs/content/en/blog/DevLog-2025.08.01/CharacterMatcher.vue index 1d0313a4c..77f329fa3 100644 --- a/docs/content/en/blog/DevLog-2025.08.01/CharacterMatcher.vue +++ b/docs/content/en/blog/DevLog-2025.08.01/CharacterMatcher.vue @@ -15,7 +15,7 @@ function interpolate(characters: string[], initial?: Character[]) { return [ ...chars, [ - ...chars.length > 0 ? chars[chars.length - 1]! : [], + ...chars.length > 0 ? chars.at(-1)! : [], { value: c, variant: 'dotted' }, ], ] diff --git a/packages/stage-pages/src/pages/devtools/beat-sync.vue b/packages/stage-pages/src/pages/devtools/beat-sync.vue index 553e12772..a9d52e542 100644 --- a/packages/stage-pages/src/pages/devtools/beat-sync.vue +++ b/packages/stage-pages/src/pages/devtools/beat-sync.vue @@ -165,7 +165,7 @@ function drawXY() { }) ctx.stroke() - const head = trail.value[trail.value.length - 1] + const head = trail.value.at(-1) if (head) { ctx.beginPath() ctx.arc(centerX + head.x * scale.value, centerY - head.y * scale.value, 5, 0, Math.PI * 2) diff --git a/packages/stage-pages/src/pages/settings/airi-card/components/CardCreationDialog.vue b/packages/stage-pages/src/pages/settings/airi-card/components/CardCreationDialog.vue index 47175f493..fcb440392 100644 --- a/packages/stage-pages/src/pages/settings/airi-card/components/CardCreationDialog.vue +++ b/packages/stage-pages/src/pages/settings/airi-card/components/CardCreationDialog.vue @@ -191,7 +191,7 @@ const tabs: Tab[] = [ const activeTab = computed({ get: () => { // If current active tab is not in available tabs, reset to first tab - if (!tabs.find(tab => tab.id === activeTabId.value)) + if (!tabs.some(tab => tab.id === activeTabId.value)) return tabs[0]?.id || '' return activeTabId.value }, diff --git a/packages/stage-pages/src/pages/settings/airi-card/components/CardDetailDialog.vue b/packages/stage-pages/src/pages/settings/airi-card/components/CardDetailDialog.vue index 6b2276725..4ad92823c 100644 --- a/packages/stage-pages/src/pages/settings/airi-card/components/CardDetailDialog.vue +++ b/packages/stage-pages/src/pages/settings/airi-card/components/CardDetailDialog.vue @@ -165,7 +165,7 @@ const tabs = computed(() => { const activeTab = computed({ get: () => { // If current active tab is not in available tabs, reset to first tab - if (!tabs.value.find(tab => tab.id === activeTabId.value)) + if (!tabs.value.some(tab => tab.id === activeTabId.value)) return tabs.value[0]?.id || '' return activeTabId.value }, diff --git a/packages/stage-pages/src/pages/settings/providers/chat/ollama.vue b/packages/stage-pages/src/pages/settings/providers/chat/ollama.vue index 2c4303efc..a05c73bdb 100644 --- a/packages/stage-pages/src/pages/settings/providers/chat/ollama.vue +++ b/packages/stage-pages/src/pages/settings/providers/chat/ollama.vue @@ -77,7 +77,7 @@ function removeKeyValue(index: number, headers: { key: string, value: string }[] } watch(headers, (headers) => { - if (headers.length > 0 && (headers[headers.length - 1].key !== '' || headers[headers.length - 1].value !== '')) { + if (headers.length > 0 && (headers.at(-1).key !== '' || headers.at(-1).value !== '')) { headers.push({ key: '', value: '' }) } if (!providers.value[providerId]) diff --git a/packages/stage-pages/src/pages/v2/settings/providers/edit/[providerId]/index.vue b/packages/stage-pages/src/pages/v2/settings/providers/edit/[providerId]/index.vue index a14707fe2..7a048a7c3 100644 --- a/packages/stage-pages/src/pages/v2/settings/providers/edit/[providerId]/index.vue +++ b/packages/stage-pages/src/pages/v2/settings/providers/edit/[providerId]/index.vue @@ -160,7 +160,7 @@ function normalizeHeaderRows(headers: Record) { if (rows.length === 0) { rows.push({ key: '', value: '' }) } - else if (rows[rows.length - 1].key !== '' || rows[rows.length - 1].value !== '') { + else if (rows.at(-1).key !== '' || rows.at(-1).value !== '') { rows.push({ key: '', value: '' }) } return rows @@ -178,7 +178,7 @@ watch(providerConfigEdit, (config) => { watch(headerRows, (rows) => { if (isSyncingHeaders.value) return - const lastRow = rows[rows.length - 1] + const lastRow = rows.at(-1) if (!lastRow || lastRow.key.trim().length > 0 || lastRow.value.trim().length > 0) { headerRows.value = [...rows, { key: '', value: '' }] return diff --git a/packages/stage-ui-live2d/src/composables/live2d/beat-sync.ts b/packages/stage-ui-live2d/src/composables/live2d/beat-sync.ts index eb38393f5..03e97c936 100644 --- a/packages/stage-ui-live2d/src/composables/live2d/beat-sync.ts +++ b/packages/stage-ui-live2d/src/composables/live2d/beat-sync.ts @@ -137,10 +137,8 @@ export function createBeatSyncController(options: CreateBeatSyncControllerOption currentZ = baseAngles.value.z } - if (currentY == null) - currentY = baseAngles.value.y - if (currentZ == null) - currentZ = baseAngles.value.z + currentY ??= baseAngles.value.y + currentZ ??= baseAngles.value.z while (segments.value.length) { const segment = segments.value[0] diff --git a/packages/stage-ui-live2d/src/utils/eye-motions.ts b/packages/stage-ui-live2d/src/utils/eye-motions.ts index f31a7c3ff..e97a8a3fd 100644 --- a/packages/stage-ui-live2d/src/utils/eye-motions.ts +++ b/packages/stage-ui-live2d/src/utils/eye-motions.ts @@ -28,5 +28,5 @@ export function randomSaccadeInterval(): number { return EYE_SACCADE_INT_P[i][1] + Math.random() * EYE_SACCADE_INT_STEP } } - return EYE_SACCADE_INT_P[EYE_SACCADE_INT_P.length - 1][1] + Math.random() * EYE_SACCADE_INT_STEP + return EYE_SACCADE_INT_P.at(-1)[1] + Math.random() * EYE_SACCADE_INT_STEP } diff --git a/packages/stage-ui-live2d/src/utils/live2d-zip-loader.ts b/packages/stage-ui-live2d/src/utils/live2d-zip-loader.ts index d06066f3e..c7a41bde1 100644 --- a/packages/stage-ui-live2d/src/utils/live2d-zip-loader.ts +++ b/packages/stage-ui-live2d/src/utils/live2d-zip-loader.ts @@ -10,7 +10,7 @@ const defaultCreateSettings = ZipLoader.createSettings ZipLoader.createSettings = async (reader: JSZip) => { const filePaths = Object.keys(reader.files) - if (!filePaths.find(file => isSettingsFile(file))) { + if (!filePaths.some(file => isSettingsFile(file))) { return createFakeSettings(filePaths) } diff --git a/packages/stage-ui-three/src/composables/shader/ibl.ts b/packages/stage-ui-three/src/composables/shader/ibl.ts index cca11c90c..1417d41a3 100644 --- a/packages/stage-ui-three/src/composables/shader/ibl.ts +++ b/packages/stage-ui-three/src/composables/shader/ibl.ts @@ -122,7 +122,7 @@ export function injectDiffuseIBL(mat: THREE.ShaderMaterial) { } // uniforms - const emptySH = Array.from({ length: 9 }, () => new THREE.Vector3()) + const emptySH = Array.from({ length: 9 }).fill(new THREE.Vector3()) shader.uniforms.uNprEnvMode ||= { value: 0 } shader.uniforms.uEnvIntensity ||= { value: 0.0 } shader.uniforms.uSHCoeffs ||= { value: emptySH }; diff --git a/packages/stage-ui-three/src/composables/vrm/utils/eye-motions.ts b/packages/stage-ui-three/src/composables/vrm/utils/eye-motions.ts index f31a7c3ff..e97a8a3fd 100644 --- a/packages/stage-ui-three/src/composables/vrm/utils/eye-motions.ts +++ b/packages/stage-ui-three/src/composables/vrm/utils/eye-motions.ts @@ -28,5 +28,5 @@ export function randomSaccadeInterval(): number { return EYE_SACCADE_INT_P[i][1] + Math.random() * EYE_SACCADE_INT_STEP } } - return EYE_SACCADE_INT_P[EYE_SACCADE_INT_P.length - 1][1] + Math.random() * EYE_SACCADE_INT_STEP + return EYE_SACCADE_INT_P.at(-1)[1] + Math.random() * EYE_SACCADE_INT_STEP } diff --git a/packages/stage-ui/src/components/form/field/field-key-values.story.vue b/packages/stage-ui/src/components/form/field/field-key-values.story.vue index b2bd109b8..e195ce95e 100644 --- a/packages/stage-ui/src/components/form/field/field-key-values.story.vue +++ b/packages/stage-ui/src/components/form/field/field-key-values.story.vue @@ -35,7 +35,7 @@ function removeKeyValue(index: number, headers: { key: string, value: string }[] } watch(emptyHeaders, (headers) => { - if (headers.length > 0 && (headers[headers.length - 1].key !== '' || headers[headers.length - 1].value !== '')) { + if (headers.length > 0 && (headers.at(-1).key !== '' || headers.at(-1).value !== '')) { emptyHeaders.value.push({ key: '', value: '' }) } }, { @@ -44,7 +44,7 @@ watch(emptyHeaders, (headers) => { }) watch(singleHeader, (headers) => { - if (headers.length > 0 && (headers[headers.length - 1].key !== '' || headers[headers.length - 1].value !== '')) { + if (headers.length > 0 && (headers.at(-1).key !== '' || headers.at(-1).value !== '')) { singleHeader.value.push({ key: '', value: '' }) } }, { @@ -53,7 +53,7 @@ watch(singleHeader, (headers) => { }) watch(multipleHeaders, (headers) => { - if (headers.length > 0 && (headers[headers.length - 1].key !== '' || headers[headers.length - 1].value !== '')) { + if (headers.length > 0 && (headers.at(-1).key !== '' || headers.at(-1).value !== '')) { multipleHeaders.value.push({ key: '', value: '' }) } }, { diff --git a/packages/stage-ui/src/components/gadgets/level-meter.vue b/packages/stage-ui/src/components/gadgets/level-meter.vue index 503cd929a..c9369f63a 100644 --- a/packages/stage-ui/src/components/gadgets/level-meter.vue +++ b/packages/stage-ui/src/components/gadgets/level-meter.vue @@ -50,7 +50,7 @@ function getBarColor(_index: number, barLevel: number): string { } } - return thresholds[thresholds.length - 1]?.color || 'bg-green-500' + return thresholds.at(-1)?.color || 'bg-green-500' } diff --git a/packages/stage-ui/src/components/gadgets/time-series-chart.vue b/packages/stage-ui/src/components/gadgets/time-series-chart.vue index 356d5875c..7e58c8b74 100644 --- a/packages/stage-ui/src/components/gadgets/time-series-chart.vue +++ b/packages/stage-ui/src/components/gadgets/time-series-chart.vue @@ -166,7 +166,7 @@ function downsampleSeries(values: readonly number[], maxPoints: number) { } // Ensure the last value remains the most recent value (avoid averaging it away) - result[result.length - 1] = values[values.length - 1] + result[result.length - 1] = values.at(-1) return result } diff --git a/packages/stage-ui/src/components/widgets/poppin-text/PoppinText.web.vue b/packages/stage-ui/src/components/widgets/poppin-text/PoppinText.web.vue index de93f5008..cc2a92c1a 100644 --- a/packages/stage-ui/src/components/widgets/poppin-text/PoppinText.web.vue +++ b/packages/stage-ui/src/components/widgets/poppin-text/PoppinText.web.vue @@ -28,7 +28,7 @@ watch(() => props.text, async (text) => { if (!text) return if (typeof text === 'string') { - targets.value = [...segmenter.segment(text)].map(seg => seg.segment) + targets.value = Array.from(segmenter.segment(text), seg => seg.segment) } else { abortController.value?.abort() diff --git a/packages/stage-ui/src/composables/use-chat-session/summary.ts b/packages/stage-ui/src/composables/use-chat-session/summary.ts index 32e2c42b9..95136e849 100644 --- a/packages/stage-ui/src/composables/use-chat-session/summary.ts +++ b/packages/stage-ui/src/composables/use-chat-session/summary.ts @@ -61,7 +61,7 @@ export function getSessionSummary( combinedReasoning: allReasoning.join('\n\n'), combinedSpeech: allSpeech.join('\n\n'), createdAt: messages[0]?.createdAt, - lastMessageAt: messages[messages.length - 1]?.createdAt, + lastMessageAt: messages.at(-1)?.createdAt, } } diff --git a/packages/stage-ui/src/composables/use-scroll-to-hash.ts b/packages/stage-ui/src/composables/use-scroll-to-hash.ts index d5f512803..921d30479 100644 --- a/packages/stage-ui/src/composables/use-scroll-to-hash.ts +++ b/packages/stage-ui/src/composables/use-scroll-to-hash.ts @@ -106,7 +106,7 @@ export function useScrollToHash( // Retry if element not yet found if (attempt < maxRetries) { - retryTimer = window.setTimeout(() => scrollToHash(hash, attempt + 1), retryDelay) + retryTimer = window.setTimeout(scrollToHash, retryDelay, hash, attempt + 1) } }) } diff --git a/packages/stage-ui/src/stores/character/orchestrator/store.ts b/packages/stage-ui/src/stores/character/orchestrator/store.ts index 2f126bb84..56ebd496f 100644 --- a/packages/stage-ui/src/stores/character/orchestrator/store.ts +++ b/packages/stage-ui/src/stores/character/orchestrator/store.ts @@ -75,7 +75,7 @@ export const useCharacterOrchestratorStore = defineStore('character-orchestrator } function enqueueSparkNotify(event: WebSocketEventOf<'spark:notify'>, options?: { reason?: string, nextRunAt?: number, maxAttempts?: number }) { - if (!pendingNotifies.value.find(item => item.data.id === event.data.id)) { + if (!pendingNotifies.value.some(item => item.data.id === event.data.id)) { pendingNotifies.value = [...pendingNotifies.value, event] } diff --git a/packages/stage-ui/src/stores/markdown-stress.ts b/packages/stage-ui/src/stores/markdown-stress.ts index 3355fbf70..8ef7e882a 100644 --- a/packages/stage-ui/src/stores/markdown-stress.ts +++ b/packages/stage-ui/src/stores/markdown-stress.ts @@ -247,7 +247,7 @@ export const useMarkdownStressStore = defineStore('markdownStress', () => { function buildForFlood() { const line = 'for for for for for' // 800 lines * 5 words = 4000 tokens - return Array.from({ length: 800 }, () => line).join('\n') + return Array.from({ length: 800 }).fill(line).join('\n') } function generateScenario(): DevtoolsChatScenario { diff --git a/packages/stage-ui/src/stores/providers.ts b/packages/stage-ui/src/stores/providers.ts index 3d89c2028..4956075ec 100644 --- a/packages/stage-ui/src/stores/providers.ts +++ b/packages/stage-ui/src/stores/providers.ts @@ -1828,7 +1828,7 @@ export const useProvidersStore = defineStore('providers', () => { const defaultOptions = metadata?.defaultOptions?.() || {} return { ...defaultOptions, - ...(Object.prototype.hasOwnProperty.call(defaultOptions, 'baseUrl') ? {} : { baseUrl: '' }), + ...(Object.hasOwn(defaultOptions, 'baseUrl') ? {} : { baseUrl: '' }), } } diff --git a/services/minecraft/src/cognitive/conscious/brain.test.ts b/services/minecraft/src/cognitive/conscious/brain.test.ts index 3505677c3..6b372258b 100644 --- a/services/minecraft/src/cognitive/conscious/brain.test.ts +++ b/services/minecraft/src/cognitive/conscious/brain.test.ts @@ -294,7 +294,7 @@ inv; const outcome = await Promise.race([ brain.processEvent({} as any, createPerceptionEvent()).then(() => 'done'), - new Promise(resolve => setTimeout(() => resolve('timeout'), 350)), + new Promise(resolve => setTimeout(resolve, 350, 'timeout')), ]) expect(outcome).toBe('done') @@ -328,7 +328,7 @@ inv; const outcome = await Promise.race([ processing, - new Promise(resolve => setTimeout(() => resolve('timeout'), 500)), + new Promise(resolve => setTimeout(resolve, 500, 'timeout')), ]) expect(outcome).toBe('done') @@ -533,11 +533,11 @@ describe('brain queue coalescing', () => { const droppedResolver = vi.fn() brain.queue = [ - ...Array.from({ length: 256 }, () => ({ + ...Array.from({ length: 256 }).fill({ event: createPerceptionEvent(), resolve: vi.fn(), reject: vi.fn(), - })), + }), { event: createNoActionFollowupEvent(), resolve: droppedResolver, @@ -557,11 +557,11 @@ describe('brain queue coalescing', () => { const feedbackResolver = vi.fn() brain.queue = [ - ...Array.from({ length: 256 }, () => ({ + ...Array.from({ length: 256 }).fill({ event: createPerceptionEvent(), resolve: vi.fn(), reject: vi.fn(), - })), + }), { event: createFeedbackEvent(), resolve: feedbackResolver, @@ -612,7 +612,7 @@ describe('brain control action queue', () => { const brain: any = new Brain(deps) const outcome = await Promise.race([ brain.processEvent({} as any, createPerceptionEvent()).then(() => 'done'), - new Promise(resolve => setTimeout(() => resolve('timeout'), 80)), + new Promise(resolve => setTimeout(resolve, 80, 'timeout')), ]) expect(outcome).toBe('done') diff --git a/services/minecraft/src/cognitive/conscious/context-summary.ts b/services/minecraft/src/cognitive/conscious/context-summary.ts index 6106f681f..420999359 100644 --- a/services/minecraft/src/cognitive/conscious/context-summary.ts +++ b/services/minecraft/src/cognitive/conscious/context-summary.ts @@ -118,7 +118,7 @@ export function collapseOldestContexts( label: `(collapsed: ${labels})`, summary: `Collapsed ${toCollapse.length} earlier contexts (${totalTurns} turns, ${totalMessages} messages). Topics: ${labels}.`, startTurnId: toCollapse[0].startTurnId, - endTurnId: toCollapse[toCollapse.length - 1].endTurnId, + endTurnId: toCollapse.at(-1).endTurnId, messageCount: totalMessages, archivedAt: Date.now(), } diff --git a/services/minecraft/src/cognitive/conscious/js-planner.ts b/services/minecraft/src/cognitive/conscious/js-planner.ts index b28f11c70..e5214d70f 100644 --- a/services/minecraft/src/cognitive/conscious/js-planner.ts +++ b/services/minecraft/src/cognitive/conscious/js-planner.ts @@ -604,7 +604,7 @@ export class JavaScriptPlanner { } private defineGlobalValue(name: string, value: unknown): void { - if (Object.prototype.hasOwnProperty.call(this.sandbox, name)) + if (Object.hasOwn(this.sandbox, name)) return Object.defineProperty(this.sandbox, name, { diff --git a/services/minecraft/src/cognitive/conscious/map-renderer.ts b/services/minecraft/src/cognitive/conscious/map-renderer.ts index 63ce6d54f..1e979c80b 100644 --- a/services/minecraft/src/cognitive/conscious/map-renderer.ts +++ b/services/minecraft/src/cognitive/conscious/map-renderer.ts @@ -304,8 +304,8 @@ function renderTopDown(bot: Bot, options: Required): MapResult { // Build the grid: each cell is [symbol, elevation_delta] const size = r * 2 + 1 - const grid: string[][] = Array.from({ length: size }, () => Array.from({ length: size }, () => ' ')) - const elevations: (number | null)[][] = Array.from({ length: size }, () => Array.from({ length: size }, () => null)) + const grid: string[][] = Array.from({ length: size }).fill(Array.from({ length: size }).fill(' ')) + const elevations: (number | null)[][] = Array.from({ length: size }).fill(Array.from({ length: size }).fill(null)) const usedCategories = new Set() for (let dz = -r; dz <= r; dz++) { @@ -454,7 +454,7 @@ function renderCrossSection(bot: Bot, options: Required): MapResult const yTop = cy + r const yBottom = cy - r - const grid: string[][] = Array.from({ length: height }, () => Array.from({ length: width }, () => ' ')) + const grid: string[][] = Array.from({ length: height }).fill(Array.from({ length: width }).fill(' ')) const usedCategories = new Set() for (let dy = -r; dy <= r; dy++) { diff --git a/services/minecraft/src/cognitive/conscious/prompts/brain-prompt.ts b/services/minecraft/src/cognitive/conscious/prompts/brain-prompt.ts index f3ecfb797..457af2ec8 100644 --- a/services/minecraft/src/cognitive/conscious/prompts/brain-prompt.ts +++ b/services/minecraft/src/cognitive/conscious/prompts/brain-prompt.ts @@ -15,8 +15,7 @@ function loadTemplateFromDisk(): string { } function ensureTemplateLoaded(): string { - if (cachedTemplate == null) - cachedTemplate = loadTemplateFromDisk() + cachedTemplate ??= loadTemplateFromDisk() return cachedTemplate } diff --git a/services/minecraft/src/cognitive/conscious/repl-code-normalizer.ts b/services/minecraft/src/cognitive/conscious/repl-code-normalizer.ts index 3a64e23fb..10859d6d2 100644 --- a/services/minecraft/src/cognitive/conscious/repl-code-normalizer.ts +++ b/services/minecraft/src/cognitive/conscious/repl-code-normalizer.ts @@ -76,7 +76,7 @@ export function normalizeReplScript(code: string): string { const hasTopLevelReturn = sourceFile.statements.some(statement => ts.isReturnStatement(statement)) if (!hasTopLevelReturn && sourceFile.statements.length > 0) { - const lastStatement = sourceFile.statements[sourceFile.statements.length - 1] + const lastStatement = sourceFile.statements.at(-1) if (ts.isExpressionStatement(lastStatement)) { const expressionText = getNodeText(sourceFile, lastStatement.expression) replacements.push({ diff --git a/services/minecraft/src/debug/tool-executor.ts b/services/minecraft/src/debug/tool-executor.ts index f74814067..223d3a87b 100644 --- a/services/minecraft/src/debug/tool-executor.ts +++ b/services/minecraft/src/debug/tool-executor.ts @@ -68,7 +68,7 @@ export class ToolExecutor { const args: any[] = [] const shape = (action.schema as any).shape for (const key in shape) { - if (Object.prototype.hasOwnProperty.call(validated, key)) { + if (Object.hasOwn(validated, key)) { args.push((validated as any)[key]) } } diff --git a/services/minecraft/src/debug/web/app.js b/services/minecraft/src/debug/web/app.js index 7d5411317..dddeabfd0 100644 --- a/services/minecraft/src/debug/web/app.js +++ b/services/minecraft/src/debug/web/app.js @@ -642,13 +642,13 @@ class ConversationPanel { handleUpdate(data) { if (data.sessionBoundary) { - const cur = this.sessions[this.sessions.length - 1] + const cur = this.sessions.at(-1) if (cur) cur.greyed = true this.sessions.push(this._mkSession()) } else { - const cur = this.sessions[this.sessions.length - 1] + const cur = this.sessions.at(-1) if (cur) { cur.messages = data.messages || [] cur.activeContext = data.activeContext || null diff --git a/services/minecraft/src/skills/patched-goto.ts b/services/minecraft/src/skills/patched-goto.ts index d655c49c7..304f5e034 100644 --- a/services/minecraft/src/skills/patched-goto.ts +++ b/services/minecraft/src/skills/patched-goto.ts @@ -213,7 +213,7 @@ export function patchedGoto( settled = true cleanup() // Resolve on next tick to let pathfinder clean up - setTimeout(() => resolve(result), 0) + setTimeout(resolve, 0, result) } function resetTimeout() { diff --git a/services/minecraft/src/utils/mcdata.ts b/services/minecraft/src/utils/mcdata.ts index 46c366144..f31cf0659 100644 --- a/services/minecraft/src/utils/mcdata.ts +++ b/services/minecraft/src/utils/mcdata.ts @@ -194,8 +194,7 @@ export function isHostile(mob: Entity): boolean { } function levenshteinDistance(a: string, b: string): number { - const matrix: number[][] = Array.from({ length: a.length + 1 }, () => - Array.from({ length: b.length + 1 }, () => 0)) + const matrix: number[][] = Array.from({ length: a.length + 1 }).fill(Array.from({ length: b.length + 1 }).fill(0)) for (let i = 0; i <= a.length; i++) matrix[i][0] = i diff --git a/services/satori-bot/src/core/loop/scheduler.ts b/services/satori-bot/src/core/loop/scheduler.ts index 8c329cd64..03e852ebe 100644 --- a/services/satori-bot/src/core/loop/scheduler.ts +++ b/services/satori-bot/src/core/loop/scheduler.ts @@ -62,9 +62,7 @@ export async function handleLoopStep( } // Manage action context size - if (chatCtx.actions == null) { - chatCtx.actions = [] - } + chatCtx.actions ??= [] chatCtx.actions = trimActions(chatCtx.actions, MAX_ACTIONS_IN_CONTEXT, ACTIONS_KEEP_ON_TRIM) } diff --git a/services/telegram-bot/src/bots/telegram/index.ts b/services/telegram-bot/src/bots/telegram/index.ts index 76a7f4986..b9d06a506 100644 --- a/services/telegram-bot/src/bots/telegram/index.ts +++ b/services/telegram-bot/src/bots/telegram/index.ts @@ -221,9 +221,7 @@ async function handleLoopStep(ctx: BotContext, chatCtx: ChatContext, incomingMes ctx.lastInteractedNChatIds = ctx.lastInteractedNChatIds.slice(-5) } - if (chatCtx.messages == null) { - chatCtx.messages = [] - } + chatCtx.messages ??= [] if (chatCtx.messages.length > 20) { const length = chatCtx.messages.length // pick the latest 5 @@ -231,9 +229,7 @@ async function handleLoopStep(ctx: BotContext, chatCtx: ChatContext, incomingMes chatCtx.messages.push(message.user(`AIRI System: Approaching to system context limit, reducing... memory..., reduced from ${length} to ${chatCtx.messages.length}, history may lost.`)) } - if (chatCtx.actions == null) { - chatCtx.actions = [] - } + chatCtx.actions ??= [] if (chatCtx.actions.length > 50) { const length = chatCtx.actions.length // pick the latest 20 diff --git a/services/twitter-services/src/adapters/mcp-adapter.ts b/services/twitter-services/src/adapters/mcp-adapter.ts index e5407f494..2fce28493 100644 --- a/services/twitter-services/src/adapters/mcp-adapter.ts +++ b/services/twitter-services/src/adapters/mcp-adapter.ts @@ -474,7 +474,7 @@ export class MCPAdapter { // Simple handling - send to most recent transport // Note: In production, should use session ID to route to correct transport - const transport = this.activeTransports[this.activeTransports.length - 1] + const transport = this.activeTransports.at(-1) // Manually handle POST message, as H3 is not Express-compatible const response = await transport.handleMessage(body)