@martini-film/cli 0.3.0 → 0.4.1

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.
Files changed (44) hide show
  1. package/README.md +169 -44
  2. package/dist/api.js +71 -23
  3. package/dist/api.js.map +1 -1
  4. package/dist/approve.js +16 -1
  5. package/dist/approve.js.map +1 -1
  6. package/dist/cli.js +487 -142
  7. package/dist/cli.js.map +1 -1
  8. package/dist/commands/assets.js +165 -29
  9. package/dist/commands/assets.js.map +1 -1
  10. package/dist/commands/call.js +131 -0
  11. package/dist/commands/call.js.map +1 -0
  12. package/dist/commands/context.js +11 -2
  13. package/dist/commands/context.js.map +1 -1
  14. package/dist/commands/files.js +117 -9
  15. package/dist/commands/files.js.map +1 -1
  16. package/dist/commands/guide.js +71 -0
  17. package/dist/commands/guide.js.map +1 -0
  18. package/dist/commands/init.js +213 -0
  19. package/dist/commands/init.js.map +1 -0
  20. package/dist/commands/login.js +37 -6
  21. package/dist/commands/login.js.map +1 -1
  22. package/dist/commands/tools.js +88 -80
  23. package/dist/commands/tools.js.map +1 -1
  24. package/dist/commands/use.js +148 -0
  25. package/dist/commands/use.js.map +1 -0
  26. package/dist/config.js +87 -6
  27. package/dist/config.js.map +1 -1
  28. package/dist/generated/guide.json +104 -0
  29. package/dist/generated/manifest.json +73 -24
  30. package/dist/guideCache.js +204 -0
  31. package/dist/guideCache.js.map +1 -0
  32. package/dist/help.js +391 -34
  33. package/dist/help.js.map +1 -1
  34. package/dist/manifest.js +27 -0
  35. package/dist/manifest.js.map +1 -1
  36. package/dist/manifestCache.js +196 -0
  37. package/dist/manifestCache.js.map +1 -0
  38. package/dist/output.js +289 -30
  39. package/dist/output.js.map +1 -1
  40. package/dist/schema.js +281 -16
  41. package/dist/schema.js.map +1 -1
  42. package/dist/wait.js +33 -2
  43. package/dist/wait.js.map +1 -1
  44. package/package.json +2 -2
@@ -0,0 +1,213 @@
1
+ import { existsSync, lstatSync, mkdirSync, readFileSync, readlinkSync, realpathSync, statSync, writeFileSync, } from 'node:fs';
2
+ import { basename, dirname, join, resolve, sep } from 'node:path';
3
+ import { flagBoolean, flagString } from '../args.js';
4
+ import { ArgumentError } from '../schema.js';
5
+ export const SKILL_MD = `---
6
+ name: martini
7
+ description: Work on Martini (AI video production) projects from the shell with the martini CLI — read boards, upload and download material, generate and wait for shots, edit project memory files. Use for any Martini task when a shell is available.
8
+ ---
9
+
10
+ # Martini CLI
11
+
12
+ ## When to use
13
+
14
+ Any Martini task: projects, canvases, shots, the library, generation, timelines, project memory files. If the
15
+ Martini MCP connector is also installed, use the CLI anyway — every MCP tool is a \`martini\` command of the same
16
+ name, with its arguments as flags, and the CLI costs no tool-listing context.
17
+
18
+ ## Install and sign in
19
+
20
+ \`\`\`bash
21
+ npm install --global @martini-film/cli # installs the CLI on PATH (or run each command as npx @martini-film/cli <command>)
22
+ martini login # pair this device in the browser (as an agent: --no-wait, relay the code, rerun)
23
+ martini whoami # which organization and key the CLI acts as
24
+ \`\`\`
25
+
26
+ Inside a Martini workflow run the CLI is already signed in through \`.martini/config.json\`; never run
27
+ \`martini login\` there.
28
+
29
+ ## Start here
30
+
31
+ \`\`\`bash
32
+ martini guide # the operator rules: read them once per session, again on a GUIDE_CHANGED warning
33
+ martini guide generation # one topic: orientation, library, timeline, generation, storage, support, shell
34
+ martini use "<project name or id>" # this directory now works in that project
35
+ martini get_board_overview # canvases, shots, library, variables
36
+ \`\`\`
37
+
38
+ \`martini use\` writes \`.martini/context.json\`, which every later command here reads: your shell is new on each
39
+ command, so an exported variable would not last. \`--project\` / \`--canvas\` override it. It holds no key.
40
+
41
+ ## Finding commands
42
+
43
+ - \`martini --help\` lists every command; \`martini <tool> --help\` shows its flags, an example, and its result
44
+ fields. Read it before a tool's first call.
45
+ - \`martini <tool> --schema <flag> --keys\` lists the keys of a JSON argument (\`--nodes\`, \`--edit\`).
46
+ - \`martini tools\` compares the server's tool list with this build's; \`martini call <tool> --args '{…}'\` sends
47
+ any tool by name.
48
+
49
+ ## Compound commands
50
+
51
+ - \`martini upload <path…>\`: local files to canvas assets; reference and frame flags take their ids.
52
+ - \`martini download <asset-id…> --dir <dir>\`: completed assets to files.
53
+ - \`martini wait <asset-id…> --timeout N\`: block until assets (or \`--job\`, \`--run\`, \`--render\`) settle.
54
+ - \`martini files pull <dir>\` / \`martini files push <dir>\`: project memory files as a directory. Push exits 1
55
+ when a file changed on the server since the pull; pull keeps a file you edited.
56
+ - \`martini probe <path|asset-id>…\`: duration, resolution, fps, codecs, sha256 (needs ffprobe).
57
+
58
+ ## Looking at results
59
+
60
+ Nothing is shown until you open a file:
61
+
62
+ \`\`\`bash
63
+ martini inspect_video --video-asset-ids <id> <id> --out-dir review # a contact sheet per shot
64
+ martini view_asset --asset-id <id> --raw --out still.webp # one image
65
+ \`\`\`
66
+
67
+ \`--out-dir\` prints \`{ dir, files: [{ path, about }] }\`; \`about\` names each file's asset, shot, and duration.
68
+
69
+ ## Output and arguments
70
+
71
+ - Results are JSON on stdout (\`guide\`, \`init\`, \`files cat\`, and \`--help\` print text); errors are one JSON
72
+ object on stderr. Exit 0 means the command did all you asked. Otherwise read \`error.code\`; work that was
73
+ done is still on stdout (a push's \`skipped\`, a wait's \`pending\`).
74
+ - \`--fields a,b.c\` keeps only those paths of the result; \`--out <path>\` writes the result to a file.
75
+ - Object arguments take JSON (\`--placement '{"rightOf": "<id>"}'\`), a list of objects takes \`@file\`
76
+ (\`--nodes @nodes.json\`), and \`--args @args.json\` passes the whole arguments object.
77
+ - An asset id works in either spelling: the bare id, or \`asset-<id>\`.
78
+
79
+ ## Waiting and approval
80
+
81
+ - Single-item generation and rendering wait by default (\`--wait\` / \`--no-wait\`). Fan a batch out, then run
82
+ \`martini wait <ids…> --timeout N\` once; a wait that runs out exits 4 and prints the resume command, and a
83
+ failed shot exits 1.
84
+ - Generations cost olives and cannot be undone: agree the plan with the user first. \`generate_nodes\`,
85
+ \`upscale_assets\`, and \`enhance_draft\` quote first; \`--approve --max-olives N\` approves under the cap in one
86
+ command. Over the cap nothing starts (exit 5): ask the user before raising it.
87
+
88
+ ## Exit codes
89
+
90
+ 0 done, all of it · 1 tool error · 2 usage · 3 auth · 4 not ready or timed out · 5 over budget (olives, or a quote over --max-olives)
91
+ `;
92
+ export const AGENTS_MD_MARKER = '## Martini CLI';
93
+ export const AGENTS_MD_POINTER = `${AGENTS_MD_MARKER}
94
+
95
+ Martini is available as the \`martini\` command; the skill at \`.agents/skills/martini/SKILL.md\` says how to use it. Start with \`martini guide\`.
96
+ `;
97
+ const SKILL_DIRECTORIES = ['.agents/skills', '.claude/skills'];
98
+ export const GITIGNORE_LINES = ['**/.martini/files.json', '**/.martini/conflicts/'];
99
+ function resolveLinks(path, depth = 0) {
100
+ try {
101
+ return realpathSync(path);
102
+ }
103
+ catch {
104
+ }
105
+ if (depth < 40) {
106
+ try {
107
+ if (lstatSync(path).isSymbolicLink())
108
+ return resolveLinks(resolve(dirname(path), readlinkSync(path)), depth + 1);
109
+ }
110
+ catch {
111
+ }
112
+ }
113
+ const parent = dirname(path);
114
+ return parent === path ? path : join(resolveLinks(parent, depth + 1), basename(path));
115
+ }
116
+ function skillTargets(root) {
117
+ const [shared, claude] = SKILL_DIRECTORIES.map(directory => join(root, directory));
118
+ const sameDirectory = existsOrLinked(claude) && resolveLinks(claude) === resolveLinks(shared);
119
+ return (sameDirectory ? [shared] : [shared, claude]).map(directory => join(directory, 'martini', 'SKILL.md'));
120
+ }
121
+ function existsOrLinked(path) {
122
+ try {
123
+ lstatSync(path);
124
+ return true;
125
+ }
126
+ catch {
127
+ return false;
128
+ }
129
+ }
130
+ function writeSkill(path, force) {
131
+ if (existsSync(path)) {
132
+ if (readFileSync(path, 'utf8') === SKILL_MD)
133
+ return 'unchanged';
134
+ if (!force)
135
+ return 'kept';
136
+ }
137
+ mkdirSync(dirname(path), { recursive: true });
138
+ writeFileSync(path, SKILL_MD);
139
+ return 'written';
140
+ }
141
+ function writeGitignore(path) {
142
+ const existing = existsSync(path) ? readFileSync(path, 'utf8') : '';
143
+ const present = new Set(existing.split(/\r?\n/).map(line => line.trim()));
144
+ const added = GITIGNORE_LINES.filter(line => !present.has(line));
145
+ if (added.length === 0)
146
+ return { path, status: 'unchanged', added: [] };
147
+ const block = ['# martini CLI: local state (martini init)', ...added].join('\n');
148
+ writeFileSync(path, `${existing.trimEnd()}${existing.trim() ? '\n\n' : ''}${block}\n`);
149
+ return { path, status: 'written', added };
150
+ }
151
+ function writePointer(path) {
152
+ const existing = existsSync(path) ? readFileSync(path, 'utf8') : '';
153
+ if (existing.includes(AGENTS_MD_MARKER))
154
+ return 'unchanged';
155
+ writeFileSync(path, `${existing.trimEnd()}${existing.trim() ? '\n\n' : ''}${AGENTS_MD_POINTER}`);
156
+ return 'written';
157
+ }
158
+ export const init = {
159
+ name: 'init',
160
+ summary: 'Install the Martini agent skill and a three-line AGENTS.md pointer in a repository (prints them without --write)',
161
+ usage: 'martini init [--write] [--force] [--dir <repo>]',
162
+ details: 'Without --write, prints the skill file, a line ---, and the AGENTS.md pointer, and writes nothing. With --write, installs the skill at <repo>/.agents/skills/martini/SKILL.md (read by Codex, Cursor, and other agents) and <repo>/.claude/skills/martini/SKILL.md (Claude Code) — only the first when .claude/skills is a link to .agents/skills — appends the pointer to <repo>/AGENTS.md (created if absent) unless it already has a "## Martini CLI" section, and adds the CLI\'s local state (.martini/files.json, .martini/conflicts/) to <repo>/.gitignore (created if absent; .martini/context.json holds no key and is meant to be committed). A skill file with other content is kept unless --force; nothing outside <repo> is written. The skill is short on purpose: it sends the agent to martini guide for the operator rules and to martini <tool> --help for flags. Result: { ok, skills: [{ path, status: written | unchanged | kept }], agentsMd: { path, status: written | unchanged }, gitignore: { path, status: written | unchanged, added } }.',
163
+ flags: [
164
+ { flag: 'write', kind: 'boolean', description: 'Install the skill and the pointer instead of printing them' },
165
+ {
166
+ flag: 'force',
167
+ kind: 'boolean',
168
+ description: 'With --write: overwrite a skill file whose content differs (an older or edited copy)',
169
+ },
170
+ {
171
+ flag: 'dir',
172
+ kind: 'string',
173
+ value: '<repo>',
174
+ description: 'With --write: the repository to install into (default: the working directory)',
175
+ },
176
+ ],
177
+ examples: ['martini init', 'martini init --write', 'martini init --write --force --dir ../my-film'],
178
+ async run(context) {
179
+ if (context.positionals.length > 0) {
180
+ throw new ArgumentError(`Unexpected argument ${JSON.stringify(context.positionals[0])}: martini init installs into a repository directory; name it with --dir <repo>.`);
181
+ }
182
+ const write = flagBoolean(context.flags, 'write') === true;
183
+ const force = flagBoolean(context.flags, 'force') === true;
184
+ const dir = flagString(context.flags, 'dir');
185
+ if (!write) {
186
+ if (force || dir !== undefined)
187
+ throw new ArgumentError('--force and --dir apply only with --write.');
188
+ return `${SKILL_MD}\n---\n\n${AGENTS_MD_POINTER}`;
189
+ }
190
+ const root = resolve(context.cwd, dir ?? '.');
191
+ if (!existsSync(root) || !statSync(root).isDirectory()) {
192
+ throw new ArgumentError(`--dir ${dir ?? root} is not a directory.`);
193
+ }
194
+ const agentsMd = join(root, 'AGENTS.md');
195
+ const gitignore = join(root, '.gitignore');
196
+ const targets = skillTargets(root);
197
+ const realRoot = realpathSync(root);
198
+ for (const path of [...targets, agentsMd, gitignore]) {
199
+ const real = resolveLinks(path);
200
+ if (real !== realRoot && !real.startsWith(`${realRoot}${sep}`)) {
201
+ throw new ArgumentError(`${path} resolves to ${real}, outside ${root} (through a link); martini init writes only inside the repository. Nothing was written.`, { hint: 'Fix the link, or install by hand from what martini init prints.' });
202
+ }
203
+ }
204
+ const skills = targets.map(path => ({ path, status: writeSkill(path, force) }));
205
+ return {
206
+ ok: true,
207
+ skills,
208
+ agentsMd: { path: agentsMd, status: writePointer(agentsMd) },
209
+ gitignore: writeGitignore(gitignore),
210
+ };
211
+ },
212
+ };
213
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,11 @@ export function defaultDeviceLabel(env = process.env) {
13
13
  export function pendingLoginPath(env = process.env) {
14
14
  return join(dirname(userConfigPath(env)), 'login-pending.json');
15
15
  }
16
+ export const PAIRING_MIN_REMAINING_MS = 120_000;
17
+ const PAIRING_GONE = new Set(['LOGIN_REQUEST_NOT_FOUND', 'LOGIN_REQUEST_EXPIRED']);
18
+ function secondsLeft(expiresAt, now) {
19
+ return Math.max(0, Math.round((new Date(expiresAt).getTime() - now) / 1000));
20
+ }
16
21
  function readPendingLogin(env, apiUrl, now) {
17
22
  const pending = readJsonFile(pendingLoginPath(env));
18
23
  if (!pending || pending.apiUrl !== apiUrl || typeof pending.pollToken !== 'string')
@@ -61,7 +66,7 @@ export const login = {
61
66
  name: 'login',
62
67
  summary: 'Sign in: pair this device through the browser and save a 90-day key',
63
68
  usage: 'martini login [--device <label>] [--profile <name>] [--no-default] [--no-wait] [--timeout <seconds>]',
64
- details: 'Prints a URL and a code. Open the URL, enter the code, approve as you (every organization you belong to — one login for all your work; saved as the profile "account") or for one organization only (saved as a profile named after it); the first profile becomes the default. Tools run as you either way and the project you name decides who is billed; an organization key additionally reaches that organization\'s REST API and is listed in its Settings. The pairing is remembered until it expires (10 minutes), so running martini login again resumes it instead of starting over — after --no-wait, a --timeout, or a shell step that was killed while the person was still approving. An agent therefore runs martini login --no-wait, tells the person the code, and runs martini login again once they have approved.',
69
+ details: "Prints a URL and a code. Open the URL, enter the code, approve as you (every organization you belong to — one login for all your work; saved as the profile \"account\") or for one organization only (saved as a profile named after it); the first profile becomes the default. Tools run as you either way and the project you name decides who is billed; an organization key additionally reaches that organization's REST API and is listed in its Settings. The pairing is remembered until it expires (10 minutes), so running martini login again resumes it instead of starting over — after --no-wait, a --timeout, or a shell step that was killed while the person was still approving; one with under two minutes left that nobody approved is replaced by a fresh code instead. An agent therefore runs martini login --no-wait, tells the person the code and how long it lasts (expiresInSeconds), and runs martini login again once they have approved. Already signed in? martini whoami prints the key's scope and configSource, the file and profile it came from (~/.config/martini/config.json by default). A key is taken from, first to last: --api-key, MARTINI_API_KEY, a .martini/config.json above the directory that holds one (a workflow run's; skipped when a profile is named), then a profile of the config file (MARTINI_CONFIG_FILE, else ~/.config/martini/config.json): --profile, MARTINI_PROFILE, else its default. --api-url (or MARTINI_API_URL) signs in to another API; the profile keeps it.",
65
70
  flags: [
66
71
  {
67
72
  flag: 'device',
@@ -87,10 +92,25 @@ export const login = {
87
92
  const apiUrl = context.config.apiUrl;
88
93
  const stderr = context.output.stderr ?? (text => process.stderr.write(text));
89
94
  let pending = readPendingLogin(env, apiUrl, context.now());
95
+ let collected = null;
96
+ if (pending && new Date(pending.expiresAt).getTime() - context.now() < PAIRING_MIN_REMAINING_MS) {
97
+ const polled = await context.client.pollLogin(pending.pollToken).catch((error) => {
98
+ if (error instanceof CliApiError && PAIRING_GONE.has(error.code))
99
+ return { status: 'expired' };
100
+ throw error;
101
+ });
102
+ if (polled.status === 'pending' || polled.status === 'expired') {
103
+ clearPendingLogin(env);
104
+ pending = null;
105
+ }
106
+ else {
107
+ collected = polled;
108
+ }
109
+ }
90
110
  if (pending) {
91
111
  stderr([
92
112
  '',
93
- ` Resuming the pairing started ${pending.startedAt}:`,
113
+ ` Resuming the pairing started ${pending.startedAt} (${secondsLeft(pending.expiresAt, context.now())} s left):`,
94
114
  ` open ${pending.verificationUrl}`,
95
115
  ` and enter the code ${pending.code}`,
96
116
  '',
@@ -112,12 +132,13 @@ export const login = {
112
132
  writePendingLogin(env, pending);
113
133
  stderr(['', ` Open ${started.verificationUrl}`, ` and enter the code ${started.code}`, ''].join('\n'));
114
134
  }
115
- if (!wantsWait(context, true)) {
135
+ if (!wantsWait(context, true) && !collected) {
116
136
  return {
117
137
  status: 'pending',
118
138
  code: pending.code,
119
139
  verificationUrl: pending.verificationUrl,
120
140
  expiresAt: pending.expiresAt,
141
+ expiresInSeconds: secondsLeft(pending.expiresAt, context.now()),
121
142
  next: 'Approve the code in the browser, then run martini login again to collect the key.',
122
143
  };
123
144
  }
@@ -132,8 +153,10 @@ export const login = {
132
153
  status: 0,
133
154
  });
134
155
  }
135
- await context.sleep(intervalMs);
136
- const polled = await context.client.pollLogin(pending.pollToken);
156
+ if (!collected)
157
+ await context.sleep(intervalMs);
158
+ const polled = collected ?? (await context.client.pollLogin(pending.pollToken));
159
+ collected = null;
137
160
  if (polled.status === 'pending') {
138
161
  if (context.now() > expiry) {
139
162
  clearPendingLogin(env);
@@ -228,7 +251,8 @@ export const whoami = {
228
251
  name: 'whoami',
229
252
  summary: 'Which key this CLI acts as — its scope, organization, and your memberships — and where the config came from',
230
253
  usage: 'martini whoami',
231
- details: 'Result: { scope, organization, organizations, key, apiVersion, apiUrl, projectId, canvasId, runId, configSource }. scope is "user" for an account key (organization is null; organizations lists every one you belong to) or "organization" for a key bound to one.',
254
+ details: 'Result: { scope, organization, organizations, key, apiVersion, apiUrl, projectId, canvasId, runId, configSource, context }. scope is "user" for an account key (organization is null; organizations lists every one you belong to) or "organization" for a key bound to one. projectId and canvasId are what commands here will use; context names the .martini/context.json they came from (martini use), with the project and canvas names, or is null when a flag, a variable, or the profile supplied them.',
255
+ readOnly: true,
232
256
  async run(context) {
233
257
  const me = await context.client.me();
234
258
  return {
@@ -244,6 +268,13 @@ export const whoami = {
244
268
  executionId: context.config.executionId ?? null,
245
269
  workerId: context.config.workerId ?? null,
246
270
  configSource: context.config.source,
271
+ context: context.config.context
272
+ ? {
273
+ file: context.config.context.path,
274
+ projectName: context.config.context.projectName ?? null,
275
+ canvasName: context.config.context.canvasName ?? null,
276
+ }
277
+ : null,
247
278
  };
248
279
  },
249
280
  };
@@ -1 +1 @@
1
- {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
@@ -5,46 +5,70 @@ import { tmpdir } from 'node:os';
5
5
  import { join } from 'node:path';
6
6
  import { CLI_VERSION, CliApiError } from '../api.js';
7
7
  import { flagBoolean, flagString } from '../args.js';
8
- import { userConfigPath } from '../config.js';
8
+ import { cacheDir, userConfigPath } from '../config.js';
9
9
  import { SUPERSEDED_BY_COMPOUND } from '../help.js';
10
- import { loadManifest } from '../manifest.js';
11
- import { ArgumentError } from '../schema.js';
12
- import { requireProject } from './context.js';
10
+ import { compareManifests } from '../manifest.js';
11
+ import { MANIFEST_REFRESH_ENV, refreshDisabled } from '../manifestCache.js';
12
+ import { ArgumentError, bareAssetId } from '../schema.js';
13
+ import { requireProject, selectedFields } from './context.js';
13
14
  export const tools = {
14
15
  name: 'tools',
15
- summary: 'List the tools this build knows (and warn when the server has a newer manifest)',
16
- usage: 'martini tools [--remote] [--fields tools.name,tools.description]',
17
- details: 'Result: { hash, serverHash, upToDate, tools: [{ name, description, readOnly, requiresActions, supersededBy? }] }. supersededBy names the compound command to prefer (upload, download). upToDate false means the server has tools or arguments this build does not know: pass such arguments with --json, or update with npx @martini-film/cli@latest.',
16
+ summary: "How the server's tool list differs from this build's (--list adds every tool commands run with)",
17
+ usage: 'martini tools [--list] [--refresh] [--remote] [--fields serverOnly,changed,tools.name]',
18
+ details: "Asks the server for its tool list first (one conditional request; MARTINI_MANIFEST_REFRESH=0 skips it) and keeps it in the local cache, so a tool or argument the server added since this build works as a command. Result: { source, hash, serverHash, fetchedAt?, upToDate, serverOnly, buildOnly, changed, count, refresh, note? } — a few hundred bytes. --list (or a tools.… path in --fields) adds tools: [{ name, description, readOnly, requiresActions, supersededBy? }], every tool with its description, about 70 KB: ask for it with --fields tools.name when the names are enough, and read one tool with martini <tool> --help. source: cache when commands run with the server's list (fetched at fetchedAt), baked when with this build's. hash: this build's manifest hash; serverHash: the server's for this key. serverOnly: tools the server has that this build lacks; buildOnly: tools this build has that the server does not list for this key (Actions tools without access, or retired ones); changed: tools whose arguments differ. upToDate: true when serverOnly and changed are both empty. Those four and serverHash are null while the server's list is unknown (offline, or MARTINI_MANIFEST_REFRESH=0 with nothing cached). With the list cached, serverOnly and changed already work as commands and flags (note says so when there are any); npx @martini-film/cli@latest updates the build itself. count is how many tools commands run with; refresh is \"on\", or \"off (MARTINI_MANIFEST_REFRESH=0)\" when nothing is fetched; supersededBy names the compound command to prefer (upload, download).",
19
+ readOnly: true,
18
20
  flags: [
21
+ {
22
+ flag: 'list',
23
+ kind: 'boolean',
24
+ description: 'Add tools: every tool commands run with, with its description (large; narrow it with --fields)',
25
+ },
26
+ { flag: 'refresh', kind: 'boolean', description: "Fetch the server's whole tool list, ignoring the cached one" },
19
27
  {
20
28
  flag: 'remote',
21
29
  kind: 'boolean',
22
- description: "Print the server's manifest (full JSON Schemas) instead of this build's list",
30
+ description: "Print the server's manifest (full JSON Schemas) instead of the summary",
23
31
  },
24
32
  ],
25
- examples: ['martini tools --fields upToDate,tools.name'],
33
+ examples: ['martini tools', 'martini tools --fields tools.name', 'martini tools --refresh --fields source,fetchedAt'],
26
34
  async run(context) {
27
- const local = context.manifest;
28
- if (flagBoolean(context.flags, 'remote'))
29
- return context.client.listTools();
30
- let serverHash = null;
31
- try {
32
- serverHash = await context.client.serverManifestHash(local.hash);
33
- }
34
- catch {
35
- serverHash = null;
35
+ const remote = flagBoolean(context.flags, 'remote') === true;
36
+ await context.manifests.refresh({ force: remote || flagBoolean(context.flags, 'refresh') === true });
37
+ if (remote) {
38
+ const known = context.manifests.state;
39
+ return known.server ?? { ...known.manifest, source: known.source };
36
40
  }
41
+ const state = context.manifests.state;
42
+ const diff = state.server ? compareManifests(state.baked, state.server) : null;
43
+ const listed = flagBoolean(context.flags, 'list') === true ||
44
+ selectedFields(context).some(path => path === 'tools' || path.startsWith('tools.'));
37
45
  return {
38
- hash: local.hash,
39
- serverHash,
40
- upToDate: serverHash === null ? null : serverHash === local.hash,
41
- tools: local.tools.map(tool => ({
42
- name: tool.name,
43
- description: tool.description,
44
- readOnly: tool.annotations.readOnlyHint,
45
- requiresActions: tool.requiresActions,
46
- ...(SUPERSEDED_BY_COMPOUND[tool.name] ? { supersededBy: SUPERSEDED_BY_COMPOUND[tool.name] } : {}),
47
- })),
46
+ source: state.source,
47
+ hash: state.baked.hash,
48
+ serverHash: state.server?.hash ?? null,
49
+ ...(state.fetchedAt ? { fetchedAt: state.fetchedAt } : {}),
50
+ upToDate: diff ? diff.serverOnly.length === 0 && diff.changed.length === 0 : null,
51
+ serverOnly: diff?.serverOnly ?? null,
52
+ buildOnly: diff?.buildOnly ?? null,
53
+ changed: diff?.changed ?? null,
54
+ count: state.manifest.tools.length,
55
+ refresh: refreshState(context.env),
56
+ ...(state.source === 'cache' && diff && diff.serverOnly.length > 0
57
+ ? {
58
+ note: `serverOnly tools are on the server but not in this build; commands run with the server's list, so they work as commands (martini ${diff.serverOnly[0]} --help).`,
59
+ }
60
+ : {}),
61
+ ...(listed
62
+ ? {
63
+ tools: state.manifest.tools.map(tool => ({
64
+ name: tool.name,
65
+ description: tool.description,
66
+ readOnly: tool.annotations.readOnlyHint,
67
+ requiresActions: tool.requiresActions,
68
+ ...(SUPERSEDED_BY_COMPOUND[tool.name] ? { supersededBy: SUPERSEDED_BY_COMPOUND[tool.name] } : {}),
69
+ })),
70
+ }
71
+ : {}),
48
72
  };
49
73
  },
50
74
  };
@@ -54,6 +78,7 @@ export const models = {
54
78
  summary: 'The model catalog (cached for an hour; --refresh to refetch; --query/--capability to narrow)',
55
79
  usage: 'martini models [--query <text>] [--capability <name>] [--detail summary|full] [--refresh]',
56
80
  details: 'get_models with a one-hour local cache per argument set (the catalog is ~10 KB and rarely changes).',
81
+ readOnly: true,
57
82
  flags: [
58
83
  {
59
84
  flag: 'query',
@@ -88,8 +113,8 @@ export const models = {
88
113
  args.capability = capability;
89
114
  if (detail)
90
115
  args.detailLevel = detail;
91
- const cacheDir = join(context.env.XDG_CACHE_HOME || join(context.env.HOME || tmpdir(), '.cache'), 'martini');
92
- const cachePath = join(cacheDir, `models-${Buffer.from(JSON.stringify(args)).toString('base64url')}.json`);
116
+ const directory = cacheDir(context.env);
117
+ const cachePath = join(directory, `models-${Buffer.from(JSON.stringify(args)).toString('base64url')}.json`);
93
118
  if (!flagBoolean(context.flags, 'refresh') && existsSync(cachePath)) {
94
119
  try {
95
120
  const cached = JSON.parse(readFileSync(cachePath, 'utf8'));
@@ -100,7 +125,7 @@ export const models = {
100
125
  }
101
126
  }
102
127
  const result = await context.client.callTool('get_models', args);
103
- mkdirSync(cacheDir, { recursive: true });
128
+ mkdirSync(directory, { recursive: true });
104
129
  writeFileSync(cachePath, JSON.stringify({ fetchedAt: context.now(), result }));
105
130
  return result;
106
131
  },
@@ -122,9 +147,13 @@ export function probeFile(path, run = spawnSync) {
122
147
  });
123
148
  }
124
149
  const parsed = JSON.parse(String(probe.stdout));
125
- const video = parsed.streams?.find(stream => stream.codec_type === 'video');
150
+ const video = parsed.streams?.find(stream => stream.codec_type === 'video' &&
151
+ stream.disposition?.attached_pic !== 1);
126
152
  const audio = parsed.streams?.find(stream => stream.codec_type === 'audio');
153
+ const kind = video ? (isStill(parsed.format?.format_name, video) ? 'image' : 'video') : audio ? 'audio' : 'unknown';
127
154
  const fps = (() => {
155
+ if (kind === 'image')
156
+ return null;
128
157
  const rate = video?.avg_frame_rate ?? video?.r_frame_rate;
129
158
  if (typeof rate !== 'string')
130
159
  return null;
@@ -134,6 +163,7 @@ export function probeFile(path, run = spawnSync) {
134
163
  const bytes = readFileSync(path);
135
164
  return {
136
165
  path,
166
+ kind,
137
167
  bytes: bytes.byteLength,
138
168
  durationSec: parsed.format?.duration ? Number(parsed.format.duration) : null,
139
169
  width: typeof video?.width === 'number' ? video.width : null,
@@ -146,11 +176,17 @@ export function probeFile(path, run = spawnSync) {
146
176
  sha256: createHash('sha256').update(bytes).digest('hex'),
147
177
  };
148
178
  }
179
+ function isStill(formatName, video) {
180
+ if (formatName && /(^|,)(image2|[a-z0-9]+_pipe)(,|$)/.test(formatName))
181
+ return true;
182
+ const codec = typeof video.codec_name === 'string' ? video.codec_name : '';
183
+ return /^(png|mjpeg|webp|bmp|tiff|gif)$/.test(codec) && Number(video.nb_frames ?? 1) <= 1 && !video.duration;
184
+ }
149
185
  export const probe = {
150
186
  name: 'probe',
151
187
  summary: 'Measure local files or assets: duration, resolution, fps, codecs, channels, sha256 (needs ffprobe)',
152
188
  usage: 'martini probe <path|asset-id>… [--dir <download-dir>]',
153
- details: 'Result: { reports: [{ path, assetId?, bytes, durationSec, width, height, fps, videoCodec, audioCodec, audioChannels, sampleRate, sha256 }] }. An argument that is not an existing file is treated as an asset id and downloaded first (needs a project).',
189
+ details: 'Result: { reports: [{ path, assetId?, kind, bytes, durationSec, width, height, fps, videoCodec, audioCodec, audioChannels, sampleRate, sha256 }] }. kind is video, audio, image (a still: fps is null), or unknown. An argument that is not an existing file is treated as an asset id and downloaded first (needs a project).',
154
190
  positionals: [
155
191
  {
156
192
  name: 'path|asset-id',
@@ -179,71 +215,43 @@ export const probe = {
179
215
  continue;
180
216
  }
181
217
  const projectId = requireProject(context);
218
+ const assetId = bareAssetId(target);
182
219
  const link = await context.client.callTool('get_asset_download_url', {
183
220
  projectId,
184
- assetId: target,
221
+ assetId,
185
222
  });
186
223
  const { bytes } = await context.client.fetchBytes(link.downloadUrl);
187
224
  mkdirSync(dir, { recursive: true });
188
- const path = join(dir, link.suggestedFilename ?? target);
225
+ const path = join(dir, link.suggestedFilename ?? assetId);
189
226
  writeFileSync(path, bytes);
190
- reports.push({ ...probeFile(path), assetId: target });
227
+ reports.push({ ...probeFile(path), assetId });
191
228
  }
192
229
  return { reports };
193
230
  },
194
231
  };
195
- const AGENTS_SNIPPET = `## Martini CLI
196
-
197
- Martini is available as the \`martini\` command (every MCP tool is a subcommand; \`martini --help\` lists them,
198
- \`martini <tool> --help\` shows a tool's flags). Prefer it over MCP tool calls for bulk, file, and wait work:
199
-
200
- - \`martini upload <files…> --canvas <id>\` uploads local files as assets in one step.
201
- - \`martini download <asset-id…> --dir out/\` saves completed assets; \`martini probe <path|id>\` measures them.
202
- - \`martini <generation tool> … --wait\` blocks until the asset is ready; \`martini wait <ids…>\` resumes a wait.
203
- - \`martini files pull dir/\` / \`martini files push dir/\` edit project memory files locally with conflict checks.
204
- - Any argument can be JSON: \`--json @args.json\`. Results are JSON on stdout; \`--fields a,b\` trims them; \`--out f\` writes them.
205
- - A wait stops at \`--timeout\` (default 50 s) with exit 4 but still prints the result and the pending ids; resume with \`martini wait <ids…> --timeout N\`, sized to your shell step.
206
- - Tools that quote first (\`generate_nodes\`, \`upscale_assets\`, \`enhance_draft\`): \`--approve --max-olives N\` takes the quote and approves it under the cap in one command; over the cap nothing starts.
207
-
208
- Exit codes: 0 ok · 1 tool error · 2 usage · 3 auth · 4 not ready or timed out · 5 insufficient olives.
209
- `;
210
- export const init = {
211
- name: 'init',
212
- summary: 'Print (or append to AGENTS.md with --write) the snippet that teaches agents to use the CLI',
213
- usage: 'martini init [--write [path]]',
214
- positionals: [{ name: 'path', description: 'With --write: the file to append to (default ./AGENTS.md)' }],
215
- flags: [
216
- {
217
- flag: 'write',
218
- kind: 'boolean',
219
- description: 'Append the snippet to the file instead of printing it (skipped when already present)',
220
- },
221
- ],
222
- async run(context) {
223
- if (flagBoolean(context.flags, 'write')) {
224
- const target = context.positionals[0] ?? join(context.cwd, 'AGENTS.md');
225
- const existing = existsSync(target) ? readFileSync(target, 'utf8') : '';
226
- if (existing.includes('## Martini CLI'))
227
- return { ok: true, path: target, changed: false };
228
- writeFileSync(target, `${existing.trimEnd()}${existing ? '\n\n' : ''}${AGENTS_SNIPPET}`);
229
- return { ok: true, path: target, changed: true };
230
- }
231
- return AGENTS_SNIPPET;
232
- },
233
- };
234
232
  export const version = {
235
233
  name: 'version',
236
- summary: 'The CLI version, the manifest hash it was built from, and the config file paths',
234
+ summary: 'The CLI version, which tool manifest commands run with, and the config file paths',
237
235
  usage: 'martini version',
238
- details: 'Result: { version, manifestHash, tools, userConfig }. martini --version prints the same.',
236
+ readOnly: true,
237
+ details: "Result: { version, manifestSource, runningManifestHash, manifestHash, cachedManifestHash, fetchedAt?, tools, refresh, manifestCache, userConfig }. runningManifestHash is the tool list commands run with: the server's list cached for this credential when manifestSource is cache (fetched at fetchedAt; the same as cachedManifestHash), this build's own when it is baked. manifestHash is always this build's, so the two differ whenever the server's list is in use and has changed since this build. tools counts the list in use; refresh is \"on\", or \"off (MARTINI_MANIFEST_REFRESH=0)\" when no command fetches the server's list; manifestCache is the cache file for this API URL and credential (null for a workflow run key or no key). Reads only local files: martini tools refreshes. martini --version prints the same.",
239
238
  async run(context) {
240
- const manifest = loadManifest();
239
+ const state = context.manifests.state;
241
240
  return {
242
241
  version: CLI_VERSION,
243
- manifestHash: manifest.hash,
244
- tools: manifest.tools.length,
242
+ manifestSource: state.source,
243
+ runningManifestHash: state.manifest.hash,
244
+ manifestHash: state.baked.hash,
245
+ cachedManifestHash: state.source === 'cache' ? state.manifest.hash : null,
246
+ ...(state.fetchedAt ? { fetchedAt: state.fetchedAt } : {}),
247
+ tools: state.manifest.tools.length,
248
+ refresh: refreshState(context.env),
249
+ manifestCache: state.cachePath,
245
250
  userConfig: userConfigPath(context.env),
246
251
  };
247
252
  },
248
253
  };
254
+ function refreshState(env) {
255
+ return refreshDisabled(env) ? `off (${MANIFEST_REFRESH_ENV}=${env[MANIFEST_REFRESH_ENV]})` : 'on';
256
+ }
249
257
  //# sourceMappingURL=tools.js.map