UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

110 lines (109 loc) • 4.75 kB
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= import { follow as slackFollow, readMany as slackReadMany, readRange as slackReadRange, readStream as slackReadStream, } from "../../core/slack/read.js"; import { readdir as slackReaddir } from "../../core/slack/readdir.js"; import { filesContaining as slackFilesContaining } from "../../core/slack/search.js"; import { stat as slackStat } from "../../core/slack/stat.js"; import {} from "../../io/types.js"; import { BaseVFS } from "../base.js"; export const VFS_MD = `\`\`\`text {prefix} channels/ <channel-name>__<channel-id>/ <yyyy-mm-dd>/ chat.jsonl # messages for that date files/ # attachments shared that day <name>__<F-id>.<ext> # cat downloads the bytes dms/ <user-name>__<dm-id>/ <yyyy-mm-dd>/ chat.jsonl files/ <name>__<F-id>.<ext> users/ <username>__<user-id>.json # user profile \`\`\` - A channel, DM or user name is \`<display-name>__<id>\`. The display name keeps Slack's spelling; only \`/\` becomes \`∕\` (U+2215). \`ls\` the parent first to find exact names, and quote a name that has spaces. - Messages are JSONL; use \`jq\` for fields such as \`.text\`, \`.user\`, \`.ts\` and \`.files\`. A day's \`files/\` may be empty. - \`.user\` is a user ID (\`U…\`), not a username; resolve it through \`users/<username>__<user-id>.json\` and filter messages by the ID. - Without \`start_time\`/\`end_time\`, a channel lists the latest 90 days up to its newest message; a date glob finds earlier days. - With \`start_time\`/\`end_time\`, listings cover that scope; messages and attachments outside it are absent, direct paths included, and \`grep\` and \`rg\` see only the in-scope files. Users and channel metadata stay available as context. - Unless \`walk_limit\` is -1, \`grep -rw\` and \`rg -w\` read only the channel and DM days Slack search names; attachments under \`files/\` are always read.`; /** * Slack's functions over its accessor, which the node and browser * packages build over their own transport. */ export class SlackVFS extends BaseVFS { readsRanges = true; wholeWordSearch = true; handed = { readdir: ['entry'], read: ['entry', 'parent'], follow: ['entry', 'parent'], readMany: ['entry', 'parent'], stat: ['entry', 'parent'], }; // Slack search names channel and DM days; users and file blobs are read as // usual. searchable = [ 'channels/*/*/chat.jsonl', 'dms/*/*/chat.jsonl', ]; readdir(path, handed) { return slackReaddir(this.accessor, path, handed?.entry, null, handed?.limit); } read(path, handed, offset = 0, size = null, signal) { const entry = handed?.entry ?? null; const parent = handed?.parent ?? null; if (offset === 0 && size === null) return slackReadStream(this.accessor, path, handed?.entry, handed?.parent, signal); return slackReadRange(this.accessor, path, entry, parent, size === null ? { offset } : { offset, size }); } readMany(paths, limit, handed) { return slackReadMany(this.accessor, paths, limit, handed); } follow(path, n, interval, handed) { return slackFollow(this.accessor, path, n, interval, handed?.entry, handed?.parent); } stat(path, handed) { return slackStat(this.accessor, path, handed?.entry, handed?.parent); } /** * Whether this VFS answers `name`; with no walk limit it reads every * file rather than ask the service's search. */ supports(name) { if (name === 'files_containing' && this.walkLimit < 0) return false; return super.supports(name); } filesContaining(path, text, opts) { if (!opts.wholeWord || this.walkLimit < 0 || !(this.accessor.transport.searchAvailable?.() ?? true)) return Promise.resolve(null); return slackFilesContaining(this.accessor, text, [path]); } } //# sourceMappingURL=slack.js.map