gipity 1.0.365 → 1.0.374

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 (52) hide show
  1. package/dist/banner.js +3 -1
  2. package/dist/commands/add.js +2 -2
  3. package/dist/commands/agent.js +3 -5
  4. package/dist/commands/approval.js +3 -3
  5. package/dist/commands/audit.js +2 -2
  6. package/dist/commands/chat.js +4 -4
  7. package/dist/commands/claude.js +8 -9
  8. package/dist/commands/credits.js +1 -1
  9. package/dist/commands/db.js +7 -6
  10. package/dist/commands/deploy.js +5 -8
  11. package/dist/commands/doctor.js +11 -13
  12. package/dist/commands/domain.js +18 -15
  13. package/dist/commands/email.js +0 -4
  14. package/dist/commands/fn.js +2 -2
  15. package/dist/commands/generate.js +57 -5
  16. package/dist/commands/job.js +6 -6
  17. package/dist/commands/location.js +7 -7
  18. package/dist/commands/login.js +2 -16
  19. package/dist/commands/logout.js +2 -3
  20. package/dist/commands/logs.js +1 -1
  21. package/dist/commands/page-eval.js +6 -4
  22. package/dist/commands/page-fetch.js +136 -0
  23. package/dist/commands/page-inspect.js +29 -27
  24. package/dist/commands/page-screenshot.js +17 -18
  25. package/dist/commands/page-test.js +8 -8
  26. package/dist/commands/page.js +6 -3
  27. package/dist/commands/plan.js +4 -4
  28. package/dist/commands/push.js +2 -6
  29. package/dist/commands/realtime.js +7 -9
  30. package/dist/commands/relay-install.js +18 -21
  31. package/dist/commands/relay.js +29 -31
  32. package/dist/commands/sandbox.js +16 -3
  33. package/dist/commands/service.js +1 -3
  34. package/dist/commands/status.js +2 -2
  35. package/dist/commands/sync.js +4 -1
  36. package/dist/commands/test.js +7 -13
  37. package/dist/commands/text.js +10 -10
  38. package/dist/commands/uninstall.js +20 -42
  39. package/dist/commands/update.js +0 -2
  40. package/dist/commands/upload.js +4 -4
  41. package/dist/commands/workflow.js +1 -2
  42. package/dist/helpers/output.js +45 -7
  43. package/dist/index.js +4 -0
  44. package/dist/knowledge.js +19 -4
  45. package/dist/progress.js +60 -0
  46. package/dist/project-setup.js +5 -1
  47. package/dist/provider-docs.js +7 -7
  48. package/dist/setup.js +20 -7
  49. package/dist/sync.js +16 -6
  50. package/dist/updater/shim.js +18 -4
  51. package/dist/upload.js +6 -0
  52. package/package.json +5 -4
package/dist/banner.js CHANGED
@@ -191,7 +191,9 @@ function renderBox(opts, outerW, bodyLines) {
191
191
  for (const row of bodyLines)
192
192
  lines.push(row);
193
193
  lines.push(border('╰') + border('─'.repeat(innerW)) + border('╯'));
194
- console.log('\n' + lines.join('\n') + '\n');
194
+ // Leading blank comes from the central output frame; keep the trailing one
195
+ // (it separates the banner from the picker/output that follows).
196
+ console.log(lines.join('\n') + '\n');
195
197
  }
196
198
  // ── Narrow layout (single panel, egg only) ────────────────────────────
197
199
  function printNarrow(opts, outerW) {
@@ -154,7 +154,7 @@ export const addCommand = new Command('add')
154
154
  console.log(JSON.stringify({ templates: { starters: STARTERS, blank: BLANK }, kits: KITS }));
155
155
  }
156
156
  else {
157
- console.log('\n' + catalogText() + '\n');
157
+ console.log(catalogText());
158
158
  }
159
159
  return;
160
160
  }
@@ -207,7 +207,7 @@ export const addCommand = new Command('add')
207
207
  console.log(success(`Scaffolded "${data.title}" (${data.type}) - ${data.files.length} files:`));
208
208
  }
209
209
  for (const f of data.files)
210
- console.log(` ${f}`);
210
+ console.log(`${f}`);
211
211
  if (data.notes?.length) {
212
212
  console.log('');
213
213
  for (const n of data.notes)
@@ -1,7 +1,7 @@
1
1
  import { Command } from 'commander';
2
2
  import { get, post, put, del } from '../api.js';
3
3
  import { requireConfig, saveConfig } from '../config.js';
4
- import { error as clrError } from '../colors.js';
4
+ import { error as clrError, success } from '../colors.js';
5
5
  import { run, printList, printResult } from '../helpers/index.js';
6
6
  import { confirm } from '../utils.js';
7
7
  export const agentCommand = new Command('agent')
@@ -51,11 +51,9 @@ agentCommand
51
51
  console.log(JSON.stringify(res.data));
52
52
  }
53
53
  else {
54
- console.log('');
55
- console.log(`Created "${res.data.name}" (${res.data.short_guid})`);
54
+ console.log(success(`Created "${res.data.name}" (${res.data.short_guid})`));
56
55
  if (opts.switch)
57
56
  console.log('Switched.');
58
- console.log('');
59
57
  }
60
58
  }));
61
59
  agentCommand
@@ -114,7 +112,7 @@ agentCommand
114
112
  const res = await get('/agents');
115
113
  const match = res.data.find(a => a.name === name || a.short_guid === name);
116
114
  if (!match) {
117
- console.error(`Agent "${name}" not found.`);
115
+ console.error(clrError(`Agent "${name}" not found.`));
118
116
  process.exit(1);
119
117
  }
120
118
  if (!await confirm(`Delete agent "${match.name}"?`)) {
@@ -1,6 +1,6 @@
1
1
  import { Command } from 'commander';
2
2
  import { get, post } from '../api.js';
3
- import { muted } from '../colors.js';
3
+ import { muted, success } from '../colors.js';
4
4
  import { run, printList, printResult } from '../helpers/index.js';
5
5
  function timeAgo(dateStr) {
6
6
  const diffMs = Date.now() - new Date(dateStr).getTime();
@@ -53,7 +53,7 @@ approvalCommand
53
53
  if (opts.expiresIn)
54
54
  body.expires_in_minutes = Number(opts.expiresIn);
55
55
  const res = await post('/approvals', body);
56
- printResult(`Created ${res.data.guid}.`, opts, res.data);
56
+ printResult(success(`Created ${res.data.guid}.`), opts, res.data);
57
57
  }));
58
58
  approvalCommand
59
59
  .command('answer <guid> [selection...]')
@@ -112,6 +112,6 @@ approvalCommand
112
112
  throw new Error('Expected approval guid like ap_xxxxxxxx');
113
113
  }
114
114
  await post(`/approvals/${guid}/cancel`, {});
115
- printResult(`Cancelled ${guid}.`, opts, { guid, cancelled: true });
115
+ printResult(success(`Cancelled ${guid}.`), opts, { guid, cancelled: true });
116
116
  }));
117
117
  //# sourceMappingURL=approval.js.map
@@ -1,7 +1,7 @@
1
1
  import { Command } from 'commander';
2
2
  import { get } from '../api.js';
3
3
  import { requireConfig } from '../config.js';
4
- import { muted } from '../colors.js';
4
+ import { muted, brand } from '../colors.js';
5
5
  import { run, printList } from '../helpers/index.js';
6
6
  export const auditCommand = new Command('audit')
7
7
  .description('Query audit logs');
@@ -47,6 +47,6 @@ auditCommand
47
47
  if (opts.entity)
48
48
  params.set('entity_type', opts.entity);
49
49
  const res = await get(`/projects/${config.projectGuid}/audit/count?${params}`);
50
- console.log(opts.json ? JSON.stringify(res.data) : `${res.data.count} events`);
50
+ console.log(opts.json ? JSON.stringify(res.data) : `${brand(String(res.data.count))} events`);
51
51
  }));
52
52
  //# sourceMappingURL=audit.js.map
@@ -2,7 +2,7 @@ import { Command } from 'commander';
2
2
  import { get, post, put, del } from '../api.js';
3
3
  import { resolveProjectContext, saveConfig } from '../config.js';
4
4
  import { sync } from '../sync.js';
5
- import { error as clrError, muted } from '../colors.js';
5
+ import { error as clrError, muted, success } from '../colors.js';
6
6
  import { run, printList, printResult } from '../helpers/index.js';
7
7
  export const chatCommand = new Command('chat')
8
8
  .description('Send a message to your agent')
@@ -95,7 +95,7 @@ chatCommand
95
95
  .action((guid, titleParts, opts) => run('Rename', async () => {
96
96
  const title = titleParts.join(' ');
97
97
  await put(`/conversations/${guid}`, { title });
98
- printResult(`Renamed ${guid} → "${title}".`, opts, { guid, title });
98
+ printResult(success(`Renamed ${guid} → "${title}".`), opts, { guid, title });
99
99
  }));
100
100
  chatCommand
101
101
  .command('archive <guid>')
@@ -103,7 +103,7 @@ chatCommand
103
103
  .option('--json', 'Output as JSON')
104
104
  .action((guid, opts) => run('Archive', async () => {
105
105
  await put(`/conversations/${guid}`, { archive: true });
106
- printResult(`Archived ${guid}.`, opts, { guid, archived: true });
106
+ printResult(success(`Archived ${guid}.`), opts, { guid, archived: true });
107
107
  }));
108
108
  chatCommand
109
109
  .command('delete <guid>')
@@ -111,6 +111,6 @@ chatCommand
111
111
  .option('--json', 'Output as JSON')
112
112
  .action((guid, opts) => run('Delete', async () => {
113
113
  await del(`/conversations/${guid}`);
114
- printResult(`Deleted ${guid}.`, opts, { guid, deleted: true });
114
+ printResult(success(`Deleted ${guid}.`), opts, { guid, deleted: true });
115
115
  }));
116
116
  //# sourceMappingURL=chat.js.map
@@ -27,6 +27,7 @@ import * as relayState from '../relay/state.js';
27
27
  import { maybeOfferRelayOn, ensureDaemonRunning } from '../relay/onboarding.js';
28
28
  import { prompt, promptBoxed, pickOne, decodeJwtExp, confirm } from '../utils.js';
29
29
  import { brand, bold, info, success, error as clrError, muted } from '../colors.js';
30
+ import { createProgressReporter } from '../progress.js';
30
31
  import { printBanner } from '../banner.js';
31
32
  import { scanForAdoption, isLikelyEmpty, canAdoptCwd, formatCwdLabel, formatBytes, adoptCurrentDir, ADOPT_THRESHOLDS, } from '../adopt-cwd.js';
32
33
  const __clDir = dirname(fileURLToPath(import.meta.url));
@@ -297,12 +298,10 @@ export const claudeCommand = new Command('claude')
297
298
  // ── Step 2: Project ───────────────────────────────────────────────
298
299
  let initialPrompt = '';
299
300
  let headlessNewProject = false;
300
- // Single status line for the (otherwise silent) sync phases, so a long
301
- // sync of a large tree no longer reads as a hang.
302
- const syncProgress = (msg) => {
303
- if (!nonInteractive)
304
- console.log(` ${muted(msg)}`);
305
- };
301
+ // One reporter for the (otherwise silent) sync phases + upload bar, so a
302
+ // long sync of a large tree no longer reads as a hang. Stays silent in
303
+ // headless (-p) runs to keep machine-readable output clean.
304
+ const syncProgress = nonInteractive ? undefined : createProgressReporter();
306
305
  let existing = getConfig();
307
306
  let forceAdoptCwd = false;
308
307
  // Ambiguity guard: a `.gipity.json` inherited from an ANCESTOR directory
@@ -394,7 +393,7 @@ export const claudeCommand = new Command('claude')
394
393
  });
395
394
  console.log(`\n Using ${projectDir}`);
396
395
  try {
397
- const result = await sync({ interactive: !nonInteractive, onProgress: syncProgress });
396
+ const result = await sync({ interactive: !nonInteractive, progress: syncProgress });
398
397
  if (result.applied > 0) {
399
398
  console.log(` Synced ${result.applied} change${result.applied > 1 ? 's' : ''} with Gipity.`);
400
399
  }
@@ -462,7 +461,7 @@ export const claudeCommand = new Command('claude')
462
461
  }
463
462
  if (doSync) {
464
463
  try {
465
- const result = await sync({ interactive: !nonInteractive, onProgress: syncProgress });
464
+ const result = await sync({ interactive: !nonInteractive, progress: syncProgress });
466
465
  if (result.applied > 0) {
467
466
  console.log(` Synced ${result.applied} change${result.applied > 1 ? 's' : ''} with Gipity.`);
468
467
  }
@@ -588,7 +587,7 @@ export const claudeCommand = new Command('claude')
588
587
  console.log(`\n Using ${projectDir}`);
589
588
  // Unified sync - push and pull resolved via three-way merge (non-fatal)
590
589
  try {
591
- const result = await sync({ interactive: !nonInteractive, onProgress: syncProgress });
590
+ const result = await sync({ interactive: !nonInteractive, progress: syncProgress });
592
591
  if (result.applied > 0) {
593
592
  console.log(` Synced ${result.applied} change${result.applied > 1 ? 's' : ''} with Gipity.`);
594
593
  }
@@ -28,7 +28,7 @@ export const creditsCommand = new Command('credits')
28
28
  if (res.data.balances.length > 0) {
29
29
  for (const b of res.data.balances) {
30
30
  const exp = new Date(b.expiresAt).toLocaleDateString();
31
- console.log(` ${b.source}: ${b.creditsRemaining.toLocaleString()} ${muted(`expires ${exp}`)}`);
31
+ console.log(`${b.source}: ${b.creditsRemaining.toLocaleString()} ${muted(`expires ${exp}`)}`);
32
32
  }
33
33
  }
34
34
  }
@@ -1,7 +1,7 @@
1
1
  import { Command } from 'commander';
2
2
  import { get, post, sendMessage } from '../api.js';
3
3
  import { requireConfig } from '../config.js';
4
- import { error as clrError } from '../colors.js';
4
+ import { error as clrError, success } from '../colors.js';
5
5
  import { run, printList } from '../helpers/index.js';
6
6
  import { confirm } from '../utils.js';
7
7
  export const dbCommand = new Command('db')
@@ -62,12 +62,10 @@ dbCommand
62
62
  console.log(JSON.stringify(res.data));
63
63
  return;
64
64
  }
65
- console.log('');
66
65
  console.log(`Databases: ${count}/${limit}`);
67
66
  console.log('');
68
67
  if (databases.length === 0) {
69
68
  console.log('No databases.');
70
- console.log('');
71
69
  return;
72
70
  }
73
71
  // Group by project
@@ -78,13 +76,16 @@ dbCommand
78
76
  grouped.set(key, []);
79
77
  grouped.get(key).push(db);
80
78
  }
79
+ let first = true;
81
80
  for (const [projectGuid, dbs] of grouped) {
81
+ if (!first)
82
+ console.log('');
83
+ first = false;
82
84
  const label = dbs[0].projectSlug || dbs[0].projectName || projectGuid;
83
85
  console.log(label);
84
86
  for (const db of dbs) {
85
- console.log(` ${db.friendlyName}`);
87
+ console.log(`${db.friendlyName}`);
86
88
  }
87
- console.log();
88
89
  }
89
90
  }
90
91
  else {
@@ -143,7 +144,7 @@ dbCommand
143
144
  console.log(JSON.stringify({ success: true }));
144
145
  }
145
146
  else {
146
- console.log(`Dropped database '${name}'.`);
147
+ console.log(success(`Dropped database '${name}'.`));
147
148
  }
148
149
  }));
149
150
  //# sourceMappingURL=db.js.map
@@ -31,8 +31,6 @@ export const deployCommand = new Command('deploy')
31
31
  }
32
32
  const config = requireConfig();
33
33
  await syncBeforeAction(opts);
34
- if (!opts.json)
35
- console.log('');
36
34
  // Call server - pipeline runs entirely server-side
37
35
  const res = await post(`/projects/${config.projectGuid}/deploy`, {
38
36
  target,
@@ -52,26 +50,26 @@ export const deployCommand = new Command('deploy')
52
50
  console.log(muted('─'.repeat(40)));
53
51
  if (d.phases && d.phases.length > 0) {
54
52
  for (const phase of d.phases) {
55
- console.log(` ${statusIcon(phase.status)} ${bold(phase.name)}: ${phase.summary}`);
53
+ console.log(`${statusIcon(phase.status)} ${bold(phase.name)}: ${phase.summary}`);
56
54
  }
57
55
  }
58
56
  else {
59
57
  // Fallback for simple deploys without phases
60
58
  const size = formatSize(d.totalBytes);
61
- console.log(` ${success('✓')} ${d.fileCount} files (${size}) → ${success(d.url)}`);
59
+ console.log(`${success('✓')} ${d.fileCount} files (${size}) → ${success(d.url)}`);
62
60
  }
63
61
  if (d.customDomains?.length) {
64
- console.log(` ${muted('Also:')} ${d.customDomains.join(', ')}`);
62
+ console.log(`${muted('Also:')} ${d.customDomains.join(', ')}`);
65
63
  }
66
64
  if (d.warning) {
67
- console.log(` ${warning(d.warning)}`);
65
+ console.log(`${warning(d.warning)}`);
68
66
  }
69
67
  // Show example curl commands for public endpoints
70
68
  if (d.examples && d.examples.length > 0) {
71
69
  console.log('');
72
70
  console.log(bold('Test your endpoints:'));
73
71
  for (const ex of d.examples) {
74
- console.log(` ${muted(ex)}`);
72
+ console.log(`${muted(ex)}`);
75
73
  }
76
74
  }
77
75
  console.log(muted('─'.repeat(40)));
@@ -83,6 +81,5 @@ export const deployCommand = new Command('deploy')
83
81
  else {
84
82
  console.log(success(`✓ Deployed to ${target}`) + muted(` (${d.elapsedMs}ms)`));
85
83
  }
86
- console.log('');
87
84
  }));
88
85
  //# sourceMappingURL=deploy.js.map
@@ -46,22 +46,20 @@ export const doctorCommand = new Command('doctor')
46
46
  const dis = updatesDisabled();
47
47
  const local = localVersion();
48
48
  const localOk = existsSync(LOCAL_ENTRY);
49
- console.log('');
50
49
  console.log(bold('Gipity CLI - doctor'));
51
50
  console.log('');
52
- console.log(` ${muted('shim version ')} ${shimVersion()}`);
53
- console.log(` ${muted('local version ')} ${local ?? dim('not installed')} ${localOk ? success('✓') : warning('(running from shim fallback)')}`);
54
- console.log(` ${muted('local install ')} ${LOCAL_PKG_DIR}`);
55
- console.log('');
56
- console.log(` ${muted('auto-updates ')} ${dis.disabled ? warning(`disabled (${dis.reason})`) : success('enabled')}`);
57
- console.log(` ${muted('settings file ')} ${existsSync(SETTINGS_FILE) ? SETTINGS_FILE : dim('(default)')} autoUpdates=${settings.autoUpdates}`);
58
- console.log(` ${muted('last check ')} ${rel(state.lastCheckAt)}`);
59
- console.log(` ${muted('last error ')} ${state.lastError ? clrError(state.lastError) : dim('none')}`);
60
- console.log(` ${muted('state file ')} ${existsSync(STATE_FILE) ? STATE_FILE : dim('(none yet)')}`);
61
- console.log(` ${muted('update log ')} ${existsSync(UPDATE_LOG) ? `${UPDATE_LOG} (${statSync(UPDATE_LOG).size} bytes)` : dim('(none yet)')}`);
51
+ console.log(`${muted('shim version ')} ${shimVersion()}`);
52
+ console.log(`${muted('local version ')} ${local ?? dim('not installed')} ${localOk ? success('✓') : warning('(running from shim fallback)')}`);
53
+ console.log(`${muted('local install ')} ${LOCAL_PKG_DIR}`);
62
54
  console.log('');
63
- console.log(dim(' Force an update with: gipity update'));
64
- console.log(dim(' Disable auto-update: export DISABLE_AUTOUPDATER=1 (or set autoUpdates: false in settings.json)'));
55
+ console.log(`${muted('auto-updates ')} ${dis.disabled ? warning(`disabled (${dis.reason})`) : success('enabled')}`);
56
+ console.log(`${muted('settings file ')} ${existsSync(SETTINGS_FILE) ? SETTINGS_FILE : dim('(default)')} autoUpdates=${settings.autoUpdates}`);
57
+ console.log(`${muted('last check ')} ${rel(state.lastCheckAt)}`);
58
+ console.log(`${muted('last error ')} ${state.lastError ? clrError(state.lastError) : dim('none')}`);
59
+ console.log(`${muted('state file ')} ${existsSync(STATE_FILE) ? STATE_FILE : dim('(none yet)')}`);
60
+ console.log(`${muted('update log ')} ${existsSync(UPDATE_LOG) ? `${UPDATE_LOG} (${statSync(UPDATE_LOG).size} bytes)` : dim('(none yet)')}`);
65
61
  console.log('');
62
+ console.log(dim('Force an update with: gipity update'));
63
+ console.log(dim('Disable auto-update: export DISABLE_AUTOUPDATER=1 (or set autoUpdates: false in settings.json)'));
66
64
  });
67
65
  //# sourceMappingURL=doctor.js.map
@@ -1,7 +1,7 @@
1
1
  import { Command } from 'commander';
2
2
  import { get, post, del } from '../api.js';
3
3
  import { getConfig, requireConfig } from '../config.js';
4
- import { error as clrError, success, muted } from '../colors.js';
4
+ import { error as clrError, success, muted, brand } from '../colors.js';
5
5
  import { run, printList } from '../helpers/index.js';
6
6
  export const domainCommand = new Command('domain')
7
7
  .description('Manage custom domains')
@@ -21,7 +21,7 @@ export const domainCommand = new Command('domain')
21
21
  console.log(JSON.stringify(res.data));
22
22
  return;
23
23
  }
24
- console.log(`Domains: ${count}/${limit}\n`);
24
+ console.log(`${muted('Domains:')} ${brand(`${count}/${limit}`)}\n`);
25
25
  if (domains.length === 0) {
26
26
  console.log('No custom domains.');
27
27
  return;
@@ -34,18 +34,21 @@ export const domainCommand = new Command('domain')
34
34
  grouped.set(key, []);
35
35
  grouped.get(key).push(d);
36
36
  }
37
+ let first = true;
37
38
  for (const [label, doms] of grouped) {
38
- console.log(label);
39
+ if (!first)
40
+ console.log('');
41
+ first = false;
42
+ console.log(brand(label));
39
43
  for (const d of doms) {
40
- console.log(` ${d.domain} ${muted(d.status)} ${muted(`[${d.shortGuid}]`)}`);
44
+ console.log(`${d.domain} ${muted(d.status)} ${muted(`[${d.shortGuid}]`)}`);
41
45
  }
42
- console.log();
43
46
  }
44
47
  }
45
48
  else {
46
49
  const config = requireConfig();
47
50
  const res = await get(`/projects/${config.projectGuid}/domains`);
48
- printList(res.data, opts, 'No custom domains configured.', d => ` ${d.domain} ${muted(d.status)} ${muted(`[${d.short_guid}]`)}`);
51
+ printList(res.data, opts, 'No custom domains configured.', d => `${d.domain} ${muted(d.status)} ${muted(`[${d.short_guid}]`)}`);
49
52
  }
50
53
  break;
51
54
  }
@@ -64,15 +67,15 @@ export const domainCommand = new Command('domain')
64
67
  console.log(success(`Domain "${data.domain.domain}" added.`));
65
68
  console.log('');
66
69
  console.log('Add this DNS record:');
67
- console.log(` Type: ${data.instructions.type}`);
68
- console.log(` Name: ${data.instructions.name}`);
69
- console.log(` Target: ${data.instructions.target}`);
70
+ console.log(`${muted('Type:'.padEnd(8))}${data.instructions.type}`);
71
+ console.log(`${muted('Name:'.padEnd(8))}${data.instructions.name}`);
72
+ console.log(`${muted('Target:'.padEnd(8))}${data.instructions.target}`);
70
73
  if (data.instructions.note) {
71
74
  console.log('');
72
75
  console.log(data.instructions.note);
73
76
  }
74
77
  console.log('');
75
- console.log(`Then run: gipity domain verify ${data.domain.short_guid}`);
78
+ console.log(muted(`Then run: gipity domain verify ${data.domain.short_guid}`));
76
79
  }
77
80
  break;
78
81
  }
@@ -121,11 +124,11 @@ export const domainCommand = new Command('domain')
121
124
  default:
122
125
  console.log('Usage: gipity domain [list|add|verify|remove]');
123
126
  console.log('');
124
- console.log(' gipity domain list List project domains');
125
- console.log(' gipity domain list --all List all domains across projects');
126
- console.log(' gipity domain add <domain.com> Add a custom domain (requires project)');
127
- console.log(' gipity domain verify <guid> Verify DNS and activate (requires project)');
128
- console.log(' gipity domain remove <guid> Remove a custom domain');
127
+ console.log(`${brand('gipity domain list')} ${muted('List project domains')}`);
128
+ console.log(`${brand('gipity domain list --all')} ${muted('List all domains across projects')}`);
129
+ console.log(`${brand('gipity domain add <domain.com>')} ${muted('Add a custom domain (requires project)')}`);
130
+ console.log(`${brand('gipity domain verify <guid>')} ${muted('Verify DNS and activate (requires project)')}`);
131
+ console.log(`${brand('gipity domain remove <guid>')} ${muted('Remove a custom domain')}`);
129
132
  }
130
133
  }));
131
134
  //# sourceMappingURL=domain.js.map
@@ -41,15 +41,11 @@ export const emailCommand = new Command('email')
41
41
  const recap = res.data.to.join(', ')
42
42
  + (res.data.cc.length ? `, cc: ${res.data.cc.join(', ')}` : '')
43
43
  + (res.data.bcc.length ? `, bcc: ${res.data.bcc.length}` : '');
44
- console.log('');
45
44
  console.log(success(`Email sent to ${recap}: ${res.data.subject}`));
46
- console.log('');
47
45
  }
48
46
  }
49
47
  catch (err) {
50
- console.log('');
51
48
  console.error(clrError(`Email failed: ${err.message}`));
52
- console.log('');
53
49
  process.exit(1);
54
50
  }
55
51
  });
@@ -14,7 +14,7 @@ fnCommand
14
14
  const res = await get(`/projects/${config.projectGuid}/functions`);
15
15
  printList(res.data, opts, 'No functions defined.', f => {
16
16
  const line = `${bold(f.name)} ${muted(`v${f.version}`)} ${muted(f.auth_level)} ${muted(`timeout=${f.timeout_ms}ms`)}`;
17
- return f.description ? `${line}\n ${muted(f.description)}` : line;
17
+ return f.description ? `${line}\n${muted(f.description)}` : line;
18
18
  });
19
19
  }));
20
20
  fnCommand
@@ -30,7 +30,7 @@ fnCommand
30
30
  const ts = new Date(log.created_at).toLocaleString();
31
31
  const statusColor = log.status === 'success' ? success : log.status === 'error' ? clrError : muted;
32
32
  const line = `${statusColor(log.status)} ${dur} ${muted(log.trigger_type || 'http')} ${muted(ts)}`;
33
- return log.error_message ? `${line}\n ${clrError(`error: ${log.error_message}`)}` : line;
33
+ return log.error_message ? `${line}\n${clrError(`error: ${log.error_message}`)}` : line;
34
34
  });
35
35
  }));
36
36
  fnCommand
@@ -28,13 +28,13 @@ Gemini-specific options:
28
28
  Examples:
29
29
  gipity generate image "a cat wearing a top hat"
30
30
  gipity generate image "landscape sunset" --provider gemini --aspect-ratio 16:9 --image-size 2K
31
- gipity generate image "product photo" --provider openai --model gpt-image-1 --size 1536x1024 --quality high
31
+ gipity generate image "product photo" --provider openai --model gpt-image-2 --size 1536x1024 --quality high
32
32
  gipity generate image "abstract art" --provider bfl --model flux-2-pro -o art.png`)
33
33
  .argument('<prompt>', 'Text description of the image to generate')
34
34
  .option('--provider <provider>', 'Image provider: openai, bfl, or gemini (default: bfl)')
35
35
  .option('--model <model>', 'Model ID (see provider list above)')
36
36
  .option('--size <size>', 'Dimensions as WxH, e.g. "1024x1024" (OpenAI/BFL)')
37
- .option('--quality <quality>', 'Quality: low|medium|high|auto (gpt-image-1), standard|hd (dall-e-3)')
37
+ .option('--quality <quality>', 'Quality: low|medium|high|auto (gpt-image-2)')
38
38
  .option('--aspect-ratio <ratio>', 'Aspect ratio (Gemini only): 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 4:5, 5:4, 21:9')
39
39
  .option('--image-size <size>', 'Output resolution (Gemini only): 512, 1K, 2K, 4K')
40
40
  .option('-o, --output <file>', 'Output path (default ./generated.png). For an image your app ships, write it into the source tree so it deploys, e.g. -o src/assets/images/hero.png; the cwd default is fine for one-off generation.')
@@ -96,7 +96,8 @@ Examples:
96
96
  .action(async (prompt, opts) => {
97
97
  try {
98
98
  const { config } = await resolveProjectContext();
99
- console.log(info('Generating video (this may take 30-120 seconds)...'));
99
+ if (!opts.json)
100
+ console.log(info('Generating video (this may take 30-120 seconds)...')); // keep --json stdout pure JSON
100
101
  const result = await post(`/projects/${config.projectGuid}/generate/video`, {
101
102
  prompt,
102
103
  model: opts.model,
@@ -178,10 +179,61 @@ Examples:
178
179
  process.exit(1);
179
180
  }
180
181
  });
182
+ // ── MUSIC ──────────────────────────────────────────────────────────────
183
+ const musicCommand = new Command('music')
184
+ .description(`Generate music from a text prompt using AI.
185
+
186
+ The model is chosen from the platform's music catalog. Omit --model to use the
187
+ default; pass --model <id> only if you want a specific one (see the catalog with
188
+ \`gipity service call music/models --get\`).
189
+
190
+ Tips:
191
+ - Describe genre, mood, instruments, and tempo (e.g. "upbeat lo-fi hip hop with mellow piano")
192
+ - Music is instrumental by default; pass --vocals to allow singing
193
+ - Longer clips cost more; the max length depends on the model
194
+
195
+ Examples:
196
+ gipity generate music "chill lo-fi beat for studying"
197
+ gipity generate music "epic orchestral battle theme" --duration 60 -o src/assets/audio/theme.mp3
198
+ gipity generate music "indie pop chorus" --vocals --duration 20`)
199
+ .argument('<prompt>', 'Text description of the music to generate')
200
+ .option('--duration <seconds>', 'Clip length in seconds (default 30; max depends on the model)', (v) => parseInt(v, 10))
201
+ .option('--model <model>', 'Music model id (default: platform default)')
202
+ .option('--vocals', 'Allow vocals (default: instrumental only)')
203
+ .option('-o, --output <file>', 'Output path (default ./music.mp3). For audio your app ships, write it into the source tree so it deploys, e.g. -o src/assets/audio/theme.mp3; the cwd default is fine for one-off generation.')
204
+ .option('--json', 'Output as JSON')
205
+ .action(async (prompt, opts) => {
206
+ try {
207
+ const { config } = await resolveProjectContext();
208
+ if (!opts.json)
209
+ console.log(info('Generating music...')); // keep --json stdout pure JSON
210
+ const result = await post(`/projects/${config.projectGuid}/generate/music`, {
211
+ prompt,
212
+ duration_seconds: opts.duration,
213
+ model: opts.model,
214
+ instrumental: !opts.vocals,
215
+ });
216
+ const filename = opts.output || 'music.mp3';
217
+ const savedPath = await downloadFile(result.url, filename);
218
+ if (opts.json) {
219
+ console.log(JSON.stringify({ ...result, saved: savedPath }));
220
+ }
221
+ else {
222
+ const sizeKb = Math.round(result.size_bytes / 1024);
223
+ console.log(`${muted(`Generated with ${result.model} (${sizeKb}KB)`)}`);
224
+ console.log(success(`Saved to ${savedPath}`));
225
+ }
226
+ }
227
+ catch (err) {
228
+ console.error(clrError(`Music generation failed: ${err.message}`));
229
+ process.exit(1);
230
+ }
231
+ });
181
232
  // ── PARENT COMMAND ─────────────────────────────────────────────────────
182
233
  export const generateCommand = new Command('generate')
183
- .description('Generate images, video, or speech')
234
+ .description('Generate images, video, speech, or music')
184
235
  .addCommand(imageCommand)
185
236
  .addCommand(videoCommand)
186
- .addCommand(speechCommand);
237
+ .addCommand(speechCommand)
238
+ .addCommand(musicCommand);
187
239
  //# sourceMappingURL=generate.js.map
@@ -17,7 +17,7 @@ jobCommand
17
17
  if (j.on_complete)
18
18
  tags.push(muted(`→ ${j.on_complete}`));
19
19
  const line = `${bold(j.name)} ${tags.join(' ')}`;
20
- return j.description ? `${line}\n ${muted(j.description)}` : line;
20
+ return j.description ? `${line}\n${muted(j.description)}` : line;
21
21
  });
22
22
  }));
23
23
  jobCommand
@@ -57,13 +57,13 @@ jobCommand
57
57
  const statusColor = r.status === 'success' ? success : r.status === 'failed' ? clrError : muted;
58
58
  console.log(`${statusColor(r.status)} ${muted(r.guid)}`);
59
59
  if (r.progress_pct != null)
60
- console.log(` progress: ${Math.round(r.progress_pct * 100)}%${r.progress_message ? ` (${r.progress_message})` : ''}`);
60
+ console.log(`progress: ${Math.round(r.progress_pct * 100)}%${r.progress_message ? ` (${r.progress_message})` : ''}`);
61
61
  if (r.duration_ms != null)
62
- console.log(` duration: ${r.duration_ms}ms`);
62
+ console.log(`duration: ${r.duration_ms}ms`);
63
63
  if (r.error)
64
- console.log(` ${clrError('error:')} ${r.error}`);
64
+ console.log(`${clrError('error:')} ${r.error}`);
65
65
  if (r.output)
66
- console.log(` output: ${JSON.stringify(r.output)}`);
66
+ console.log(`output: ${JSON.stringify(r.output)}`);
67
67
  }));
68
68
  jobCommand
69
69
  .command('runs <name>')
@@ -78,7 +78,7 @@ jobCommand
78
78
  const dur = r.duration_ms != null ? `${r.duration_ms}ms` : '?';
79
79
  const ts = new Date(r.created_at).toLocaleString();
80
80
  const line = `${statusColor(r.status)} ${dur} ${muted(r.trigger_type)} ${muted(r.guid)} ${muted(ts)}`;
81
- return r.error ? `${line}\n ${clrError(`error: ${r.error}`)}` : line;
81
+ return r.error ? `${line}\n${clrError(`error: ${r.error}`)}` : line;
82
82
  });
83
83
  }));
84
84
  jobCommand
@@ -12,16 +12,16 @@ function formatLocation(r) {
12
12
  const lines = [];
13
13
  const place = [r.city, r.region, r.country].filter(Boolean).join(', ');
14
14
  if (place)
15
- lines.push(` ${place}`);
15
+ lines.push(place);
16
16
  if (r.lat != null && r.lon != null)
17
- lines.push(` Coordinates: ${r.lat}, ${r.lon}`);
17
+ lines.push(`Coordinates: ${r.lat}, ${r.lon}`);
18
18
  if (r.ip)
19
- lines.push(` IP: ${r.ip}`);
19
+ lines.push(`IP: ${r.ip}`);
20
20
  if (r.timezone)
21
- lines.push(` Timezone: ${r.timezone}`);
21
+ lines.push(`Timezone: ${r.timezone}`);
22
22
  if (r.accuracy != null)
23
- lines.push(` Accuracy: ${Math.round(r.accuracy)}m`);
24
- lines.push(` Source: ${r.source}`);
23
+ lines.push(`Accuracy: ${Math.round(r.accuracy)}m`);
24
+ lines.push(`Source: ${r.source}`);
25
25
  return lines.join('\n');
26
26
  }
27
27
  /**
@@ -71,7 +71,7 @@ export const locationCommand = new Command('location')
71
71
  return;
72
72
  }
73
73
  if (!res.data) {
74
- console.log(' No location data.');
74
+ console.log('No location data.');
75
75
  return;
76
76
  }
77
77
  console.log(formatLocation(res.data));