@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
151 lines • 7.4 kB
JavaScript
// ========= 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 { AirtableAccessor } from "../../../../accessor/airtable.js";
import { AirtableConfig } from "../../../../core/airtable/config.js";
import { Argument, CommandSpec } from "../../../spec/types.js";
import { CLI, CLIHandler } from "../../types.js";
import * as reads from "./reads.js";
import * as writes from "./writes.js";
const BASE_OPTION = new Argument('--base', { required: true, help: 'Base ID (app...)' });
const TABLE_OPTION = new Argument('--table', { required: true, help: 'Table ID or name' });
const FIELDS_OPTION = new Argument('--fields', {
help: 'Cell values as a JSON object keyed by field name',
});
const TYPECAST_OPTION = new Argument('--typecast', {
action: 'store_true',
help: 'Let Airtable convert string values to the field types',
});
const RECORD = new Argument('RECORD', { nargs: '?' });
const CREATE_EPILOG = 'Without --fields, reads records.jsonl lines from stdin and creates one\n' +
'record per line from its "fields"; computed fields are dropped.';
const UPDATE_EPILOG = 'Without RECORD --fields, reads records.jsonl lines from stdin and patches\n' +
'each "record_id" with its "fields"; computed fields are dropped.';
const DELETE_EPILOG = 'Without RECORD operands, reads records.jsonl lines from stdin and deletes\n' +
'each "record_id".';
// The airtable program tree. Bases, tables and records are addressed by the
// ids the mount prints after the last "__" of a directory name; a write takes
// one record from flags or many as JSONL on stdin, the shape records.jsonl
// holds. Install with an AirtableConfig.
export const AIRTABLE = new CLI({
spec: new CommandSpec({
name: 'airtable',
description: 'Airtable Web API client',
subcommands: [
new CommandSpec({
name: 'base',
description: 'Read bases',
subcommands: [
new CommandSpec({
name: 'list',
description: 'List the bases the token reaches as JSON',
}),
new CommandSpec({
name: 'get',
description: 'Get one base and its tables (base.json)',
arguments: [new Argument('BASE', { nargs: '?' })],
}),
],
}),
new CommandSpec({
name: 'table',
description: 'Read table schemas',
subcommands: [
new CommandSpec({
name: 'get',
description: "Get one table's fields and views (table.json)",
arguments: [BASE_OPTION, new Argument('TABLE', { nargs: '?' })],
}),
],
}),
new CommandSpec({
name: 'record',
description: 'Read and write records',
subcommands: [
new CommandSpec({
name: 'list',
description: 'List records as JSONL (records.jsonl)',
arguments: [
BASE_OPTION,
TABLE_OPTION,
new Argument('--view', { help: 'View ID or name; its filter and sort apply' }),
new Argument('--formula', {
help: 'Only the records this formula is true for (filterByFormula)',
}),
new Argument('--max-records', { type: 'int', help: 'Stop after N records' }),
],
}),
new CommandSpec({
name: 'get',
description: 'Get one record as a JSONL line',
arguments: [BASE_OPTION, TABLE_OPTION, RECORD],
}),
new CommandSpec({
name: 'create',
description: 'Create records from --fields or stdin',
arguments: [BASE_OPTION, TABLE_OPTION, FIELDS_OPTION, TYPECAST_OPTION],
epilog: CREATE_EPILOG,
}),
new CommandSpec({
name: 'update',
description: "Update records' cells (PATCH) from RECORD --fields or stdin",
arguments: [BASE_OPTION, TABLE_OPTION, FIELDS_OPTION, TYPECAST_OPTION, RECORD],
epilog: UPDATE_EPILOG,
}),
new CommandSpec({
name: 'delete',
description: 'Delete records by RECORD or from stdin',
arguments: [BASE_OPTION, TABLE_OPTION, new Argument('RECORD', { nargs: '*' })],
epilog: DELETE_EPILOG,
}),
],
}),
new CommandSpec({
name: 'comment',
description: 'Read and add record comments',
subcommands: [
new CommandSpec({
name: 'list',
description: "List a record's comments, newest first",
arguments: [BASE_OPTION, TABLE_OPTION, RECORD],
}),
new CommandSpec({
name: 'add',
description: 'Comment on a record',
arguments: [
BASE_OPTION,
TABLE_OPTION,
new Argument('--text', { help: 'Comment text (or pipe via stdin)' }),
RECORD,
],
}),
],
}),
],
}),
handlers: {
'base list': new CLIHandler({ fn: reads.baseList }),
'base get': new CLIHandler({ fn: reads.baseGet }),
'table get': new CLIHandler({ fn: reads.tableGet }),
'record list': new CLIHandler({ fn: reads.recordList }),
'record get': new CLIHandler({ fn: reads.recordGet }),
'record create': new CLIHandler({ fn: writes.recordCreate, write: true }),
'record update': new CLIHandler({ fn: writes.recordUpdate, write: true }),
'record delete': new CLIHandler({ fn: writes.recordDelete, write: true }),
'comment list': new CLIHandler({ fn: reads.commentList }),
'comment add': new CLIHandler({ fn: writes.commentAdd, write: true }),
},
configModel: AirtableConfig,
accessor: (config) => new AirtableAccessor(config),
});
//# sourceMappingURL=index.js.map