@myapihq/cli 1.2.8 → 1.3.0

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 (36) hide show
  1. package/dist/commands/email/index.js +1 -0
  2. package/dist/commands/email/mailbox.js +28 -1
  3. package/dist/commands/email/verify.d.ts +2 -2
  4. package/dist/commands/email/verify.js +85 -16
  5. package/dist/commands/git.d.ts +22 -0
  6. package/dist/commands/git.js +367 -0
  7. package/dist/commands/pixel.js +6 -3
  8. package/dist/commands/queue-validation.test.d.ts +1 -0
  9. package/dist/commands/queue-validation.test.js +38 -0
  10. package/dist/commands/queue.d.ts +14 -0
  11. package/dist/commands/queue.js +215 -0
  12. package/dist/commands/task-validation.test.d.ts +1 -0
  13. package/dist/commands/task-validation.test.js +37 -0
  14. package/dist/commands/task.d.ts +18 -0
  15. package/dist/commands/task.js +288 -0
  16. package/dist/commands/workflow-validation.test.js +27 -0
  17. package/dist/commands/workflow.js +17 -1
  18. package/dist/completion.js +6 -3
  19. package/dist/exposes.test.js +3 -0
  20. package/dist/index.js +21 -0
  21. package/dist/sdk-email-forwarding.test.d.ts +1 -0
  22. package/dist/sdk-email-forwarding.test.js +48 -0
  23. package/dist/sdk-email-verify-bulk.test.d.ts +1 -0
  24. package/dist/sdk-email-verify-bulk.test.js +57 -0
  25. package/dist/sdk-git.test.d.ts +1 -0
  26. package/dist/sdk-git.test.js +115 -0
  27. package/dist/sdk-queue.test.d.ts +1 -0
  28. package/dist/sdk-queue.test.js +86 -0
  29. package/dist/sdk-task.test.d.ts +1 -0
  30. package/dist/sdk-task.test.js +110 -0
  31. package/dist/skills/my-email-api/README.md +45 -0
  32. package/dist/skills/my-email-api/SKILL.md +80 -0
  33. package/dist/skills/my-email-api/claude/.claude-plugin/plugin.json +6 -0
  34. package/dist/skills/my-email-api/openapi/.gitkeep +0 -0
  35. package/dist/skills/my-workflow-api/SKILL.md +10 -1
  36. package/package.json +2 -2
@@ -31,6 +31,7 @@ export const SCHEMA = {
31
31
  prompt: 'string',
32
32
  name: 'string',
33
33
  emails: 'string',
34
+ quick: 'boolean',
34
35
  'per-day': 'number',
35
36
  file: 'string',
36
37
  };
@@ -4,6 +4,8 @@ import { success, error, printTable, info } from '../../output.js';
4
4
  export const EXPOSES = [
5
5
  'POST /email/mailboxes/create',
6
6
  'GET /email/mailboxes',
7
+ 'PUT /email/mailboxes/{address}/forwarding',
8
+ 'DELETE /email/mailboxes/{address}/forwarding',
7
9
  'POST /email/sending/activate',
8
10
  ];
9
11
  async function create(addressArg, flags) {
@@ -52,6 +54,22 @@ async function activateSending(flags) {
52
54
  const res = await sdkEmail.activateSending(config.api_key, address);
53
55
  success(`Sending activated: ${address} (${res.emails_quota_remaining} emails/day quota)`);
54
56
  }
57
+ async function setForwarding(address, forwardTo, _flags) {
58
+ const config = requireConfig();
59
+ if (!address || !forwardTo) {
60
+ error('Missing required arguments.\nUsage: myapi email mailbox set-forwarding <user@domain> <forward-to@domain>');
61
+ }
62
+ const res = await sdkEmail.setForwarding(config.api_key, address, forwardTo);
63
+ success(`Forwarding set: ${res.address} → ${res.forward_to}`);
64
+ info('A copy of every incoming message is redirected; the original is kept in the mailbox.');
65
+ }
66
+ async function clearForwarding(address, _flags) {
67
+ const config = requireConfig();
68
+ if (!address)
69
+ error('Missing required arguments.\nUsage: myapi email mailbox clear-forwarding <user@domain>');
70
+ await sdkEmail.deleteForwarding(config.api_key, address);
71
+ success(`Forwarding cleared for ${address}`);
72
+ }
55
73
  const USAGE = {
56
74
  'create': `myapi email mailbox create <user@domain> [--display-name <name>]
57
75
  myapi email mailbox create --username <u> --domain <d> [--display-name <name>]
@@ -65,6 +83,11 @@ matches the rest of the CLI ("first required arg is positional").`,
65
83
  org (orphaned mailboxes — domain was unassigned
66
84
  without first deleting them).`,
67
85
  'activate-sending': 'myapi email mailbox activate-sending --address <email>',
86
+ 'set-forwarding': `myapi email mailbox set-forwarding <user@domain> <forward-to@domain>
87
+
88
+ Redirects a copy of every incoming message to an external address
89
+ (server-side). The original is kept in the mailbox.`,
90
+ 'clear-forwarding': 'myapi email mailbox clear-forwarding <user@domain>',
68
91
  };
69
92
  export async function run(sub, args, flags) {
70
93
  if (!sub || (flags.help && !sub)) {
@@ -73,7 +96,9 @@ export async function run(sub, args, flags) {
73
96
  Subcommands:
74
97
  create Create a mailbox (positional <user@domain> or --username/--domain)
75
98
  list List mailboxes on a domain (--domain) or orphaned ones (--filter unassigned)
76
- activate-sending Activate outbound sending for a mailbox`);
99
+ activate-sending Activate outbound sending for a mailbox
100
+ set-forwarding Forward a copy of incoming mail to an external address
101
+ clear-forwarding Stop forwarding for a mailbox`);
77
102
  return;
78
103
  }
79
104
  if (flags.help) {
@@ -88,6 +113,8 @@ Subcommands:
88
113
  case 'create': return create(args[0], flags);
89
114
  case 'list': return list(flags);
90
115
  case 'activate-sending': return activateSending(flags);
116
+ case 'set-forwarding': return setForwarding(args[0], args[1], flags);
117
+ case 'clear-forwarding': return clearForwarding(args[0], flags);
91
118
  default: error(`Unknown subcommand: ${sub}. Run "myapi email mailbox --help" for the list.`);
92
119
  }
93
120
  }
@@ -3,5 +3,5 @@ import { type Flags } from '../../helpers.js';
3
3
  import type { Exposes } from '../../exposes.js';
4
4
  export declare const EXPOSES: Exposes;
5
5
  export declare const SCHEMA: FlagSchema;
6
- export declare const VERIFY_HELP = "Usage: myapi email verify <email> [--org <id>] [--json]\n\nSync single-address email verification. Cheap layer only: syntax + DNS +\nMicrosoft GetCredentialType. Returns a verdict in <1s for ~50% of inputs;\nthe rest get verdict='unknown' with smtp_recommended=true.\n\nVerdicts:\n deliverable high-confidence \u2014 the address accepts mail\n undeliverable high-confidence \u2014 syntax bad, DNS missing, or Microsoft rejects\n unknown not enough signal; consider an SMTP probe (not in this API)\n\nUse --json for the full check breakdown (syntax / DNS / Microsoft probes).\n";
7
- export declare function run(emailArg: string | undefined, _rest: string[], flags?: Flags): Promise<void>;
6
+ export declare const VERIFY_HELP = "Usage: myapi email verify <email> [--org <id>] [--json]\n myapi email verify bulk [--quick] [--org <id>] < emails.txt\n myapi email verify job <job_id> [--org <id>] [--json]\n\nSingle-address verification (sync): syntax + DNS + Microsoft probe.\nReturns a verdict in <1s for ~50% of inputs; the rest get\nverdict='unknown' with smtp_recommended=true.\n\nBulk verification (async): reads up to 500 addresses from stdin (one per\nline), starts a job, and prints a job_id. It runs the cheap verdict on\nevery address then SMTP-probes the uncertain ones. --quick skips the\ncatch-all check (faster, but catch-all domains aren't flagged). Poll with\n\"myapi email verify job <job_id>\".\n";
7
+ export declare function run(arg: string | undefined, rest: string[], flags?: Flags): Promise<void>;
@@ -1,31 +1,85 @@
1
1
  import { email as sdkEmail } from '@myapihq/sdk';
2
2
  import { requireConfig } from '../../config.js';
3
- import { error, info, printJson } from '../../output.js';
3
+ import { success, error, info, printTable, printJson } from '../../output.js';
4
4
  import { requireOrg } from '../../helpers.js';
5
5
  export const EXPOSES = [
6
6
  'POST /email/orgs/{org_id}/verify',
7
+ 'POST /email/orgs/{org_id}/verify-bulk',
8
+ 'GET /email/orgs/{org_id}/verify-jobs/{id}',
7
9
  ];
8
10
  export const SCHEMA = {};
9
11
  export const VERIFY_HELP = `Usage: myapi email verify <email> [--org <id>] [--json]
12
+ myapi email verify bulk [--quick] [--org <id>] < emails.txt
13
+ myapi email verify job <job_id> [--org <id>] [--json]
10
14
 
11
- Sync single-address email verification. Cheap layer only: syntax + DNS +
12
- Microsoft GetCredentialType. Returns a verdict in <1s for ~50% of inputs;
13
- the rest get verdict='unknown' with smtp_recommended=true.
15
+ Single-address verification (sync): syntax + DNS + Microsoft probe.
16
+ Returns a verdict in <1s for ~50% of inputs; the rest get
17
+ verdict='unknown' with smtp_recommended=true.
14
18
 
15
- Verdicts:
16
- deliverable high-confidence the address accepts mail
17
- undeliverable high-confidence syntax bad, DNS missing, or Microsoft rejects
18
- unknown not enough signal; consider an SMTP probe (not in this API)
19
-
20
- Use --json for the full check breakdown (syntax / DNS / Microsoft probes).
19
+ Bulk verification (async): reads up to 500 addresses from stdin (one per
20
+ line), starts a job, and prints a job_id. It runs the cheap verdict on
21
+ every address then SMTP-probes the uncertain ones. --quick skips the
22
+ catch-all check (faster, but catch-all domains aren't flagged). Poll with
23
+ "myapi email verify job <job_id>".
21
24
  `;
22
- export async function run(emailArg, _rest, flags = {}) {
23
- if (flags.help) {
24
- info(VERIFY_HELP);
25
+ async function readStdinLines() {
26
+ if (process.stdin.isTTY) {
27
+ error('No input on stdin. Pipe a newline-separated list of addresses:\n myapi email verify bulk < emails.txt');
28
+ }
29
+ const data = await new Promise((resolve, reject) => {
30
+ let buf = '';
31
+ process.stdin.setEncoding('utf-8');
32
+ process.stdin.on('data', c => { buf += c; });
33
+ process.stdin.on('end', () => resolve(buf));
34
+ process.stdin.on('error', reject);
35
+ });
36
+ return data.split('\n').map(l => l.trim()).filter(Boolean);
37
+ }
38
+ async function bulk(flags) {
39
+ const config = requireConfig();
40
+ const orgId = requireOrg(flags, config, 'myapi email verify bulk [--quick] [--org <id>] < emails.txt');
41
+ const emails = await readStdinLines();
42
+ if (emails.length === 0)
43
+ error('No addresses on stdin. Provide a newline-separated list.');
44
+ if (emails.length > 500)
45
+ error(`Too many addresses (${emails.length}). The bulk limit is 500 per job.`);
46
+ // --quick turns off the catch-all check (catchAll=false).
47
+ const job = await sdkEmail.verifyBulk(config.api_key, orgId, emails, flags.quick ? false : undefined);
48
+ if (flags.json) {
49
+ printJson(job);
50
+ return;
51
+ }
52
+ success(`Bulk verification started — ${job.total} address(es)`);
53
+ info(`Job: ${job.job_id} · status: ${job.status}`);
54
+ info(`Poll it with: myapi email verify job ${job.job_id}`);
55
+ }
56
+ async function job(jobId, flags) {
57
+ if (!jobId)
58
+ error('Missing job id.\nUsage: myapi email verify job <job_id>');
59
+ const config = requireConfig();
60
+ const orgId = requireOrg(flags, config, 'myapi email verify job <job_id> [--org <id>]');
61
+ const res = await sdkEmail.getVerifyJob(config.api_key, orgId, jobId);
62
+ if (flags.json) {
63
+ printJson(res);
25
64
  return;
26
65
  }
27
- if (!emailArg)
28
- error('Missing required argument <email>.\nUsage: myapi email verify <email> [--org <id>] [--json]');
66
+ info(`Job: ${res.job_id}`);
67
+ info(`Status: ${res.status}`);
68
+ info(`Progress: ${res.completed ?? 0} / ${res.total}`);
69
+ if (res.error)
70
+ info(`Error: ${res.error}`);
71
+ if (res.results && res.results.length > 0) {
72
+ info('');
73
+ printTable(res.results.map(r => ({
74
+ email: r.email,
75
+ verdict: r.verdict,
76
+ confidence: r.confidence.toFixed(2),
77
+ source: r.source,
78
+ detail: r.detail || '',
79
+ })), { flags });
80
+ }
81
+ }
82
+ async function single(emailArg, flags) {
29
83
  const config = requireConfig();
30
84
  const orgId = requireOrg(flags, config, 'myapi email verify <email> [--org <id>]');
31
85
  const res = await sdkEmail.verifyEmail(config.api_key, orgId, emailArg);
@@ -38,7 +92,7 @@ export async function run(emailArg, _rest, flags = {}) {
38
92
  : '? unknown';
39
93
  info(`Email: ${res.email}`);
40
94
  info(`Verdict: ${verdictLabel} (confidence ${res.confidence.toFixed(2)})`);
41
- info(`SMTP next: ${res.smtp_recommended ? 'yes — consider an SMTP probe' : 'no — verdict is definitive'}`);
95
+ info(`SMTP next: ${res.smtp_recommended ? 'yes — consider a bulk job (SMTP-probes the uncertain ones)' : 'no — verdict is definitive'}`);
42
96
  info(`Took: ${res.elapsed_ms}ms`);
43
97
  if (res.checks.syntax.detail)
44
98
  info(`Syntax: ${res.checks.syntax.detail}`);
@@ -50,3 +104,18 @@ export async function run(emailArg, _rest, flags = {}) {
50
104
  if (res.checks.microsoft)
51
105
  info(`Microsoft: ${res.checks.microsoft.verdict}`);
52
106
  }
107
+ // `arg` is the first token after `verify`: the literal `bulk` / `job`
108
+ // selects the async modes; anything else is treated as a single address.
109
+ export async function run(arg, rest, flags = {}) {
110
+ if (flags.help) {
111
+ info(VERIFY_HELP);
112
+ return;
113
+ }
114
+ if (arg === 'bulk')
115
+ return bulk(flags);
116
+ if (arg === 'job')
117
+ return job(rest[0], flags);
118
+ if (!arg)
119
+ error('Missing required argument <email>.\nUsage: myapi email verify <email> (or: verify bulk | verify job <id>)');
120
+ return single(arg, flags);
121
+ }
@@ -0,0 +1,22 @@
1
+ import type { FlagSchema } from '../flags.js';
2
+ import { type Flags } from '../helpers.js';
3
+ import type { Exposes } from '../exposes.js';
4
+ export declare const EXPOSES: Exposes;
5
+ export declare const SCHEMA: FlagSchema;
6
+ export declare function create(name: string, flags: Flags): Promise<void>;
7
+ export declare function list(flags: Flags): Promise<void>;
8
+ export declare function get(repo: string, flags: Flags): Promise<void>;
9
+ export declare function del(repo: string, flags: Flags): Promise<void>;
10
+ export declare function refs(repo: string, flags: Flags): Promise<void>;
11
+ export declare function log(repo: string, flags: Flags): Promise<void>;
12
+ export declare function show(repo: string, sha: string, flags: Flags): Promise<void>;
13
+ export declare function tree(repo: string, ref: string, flags: Flags): Promise<void>;
14
+ export declare function blob(repo: string, ref: string, path: string, flags: Flags): Promise<void>;
15
+ export declare function diff(repo: string, flags: Flags): Promise<void>;
16
+ export declare function commit(repo: string, flags: Flags): Promise<void>;
17
+ export declare function createBranch(repo: string, name: string, flags: Flags): Promise<void>;
18
+ export declare function deleteBranch(repo: string, branch: string, flags: Flags): Promise<void>;
19
+ export declare function tag(repo: string, name: string, flags: Flags): Promise<void>;
20
+ export declare function merge(repo: string, flags: Flags): Promise<void>;
21
+ export declare function repack(repo: string, flags: Flags): Promise<void>;
22
+ export declare function run(subcommand: string | undefined, args: string[], flags: Flags): Promise<void>;
@@ -0,0 +1,367 @@
1
+ import { git as sdkGit } from '@myapihq/sdk';
2
+ import { requireConfig } from '../config.js';
3
+ import { success, error, printTable, info, printJson } from '../output.js';
4
+ import { formatDate } from '../utils.js';
5
+ import { requireOrg, requireArg } from '../helpers.js';
6
+ export const EXPOSES = [
7
+ 'POST /git/orgs/{org_id}/repos',
8
+ 'GET /git/orgs/{org_id}/repos',
9
+ 'GET /git/orgs/{org_id}/repos/{repo}',
10
+ 'DELETE /git/orgs/{org_id}/repos/{repo}',
11
+ 'GET /git/orgs/{org_id}/repos/{repo}/refs',
12
+ 'GET /git/orgs/{org_id}/repos/{repo}/tree/{ref}',
13
+ 'GET /git/orgs/{org_id}/repos/{repo}/blob/{ref}/{path}',
14
+ 'GET /git/orgs/{org_id}/repos/{repo}/commits',
15
+ 'GET /git/orgs/{org_id}/repos/{repo}/commits/{sha}',
16
+ 'GET /git/orgs/{org_id}/repos/{repo}/diff',
17
+ 'POST /git/orgs/{org_id}/repos/{repo}/commits',
18
+ 'POST /git/orgs/{org_id}/repos/{repo}/branches',
19
+ 'DELETE /git/orgs/{org_id}/repos/{repo}/branches/{branch}',
20
+ 'POST /git/orgs/{org_id}/repos/{repo}/tags',
21
+ 'POST /git/orgs/{org_id}/repos/{repo}/merges',
22
+ 'POST /git/orgs/{org_id}/repos/{repo}/repack',
23
+ ];
24
+ export const SCHEMA = {
25
+ name: 'string',
26
+ 'default-branch': 'string',
27
+ ref: 'string',
28
+ limit: 'number',
29
+ path: 'string',
30
+ base: 'string',
31
+ head: 'string',
32
+ branch: 'string',
33
+ message: 'string',
34
+ from: 'string',
35
+ 'author-name': 'string',
36
+ 'author-email': 'string',
37
+ changes: 'string',
38
+ target: 'string',
39
+ source: 'string',
40
+ };
41
+ const shortSha = (s) => (s || '').slice(0, 8);
42
+ const firstLine = (s) => (s || '').split('\n')[0];
43
+ // ── Repos ────────────────────────────────────────────────────────────────────
44
+ export async function create(name, flags) {
45
+ const config = requireConfig();
46
+ const orgId = requireOrg(flags, config, 'myapi git create <name> [--default-branch <b>] [--org <id>]');
47
+ const repoName = name || flags.name;
48
+ requireArg(repoName, 'name', 'myapi git create <name> [--default-branch <b>]');
49
+ const res = await sdkGit.createRepo(config.api_key, orgId, repoName, flags['default-branch']);
50
+ success(`Repository created: ${res.name}`);
51
+ info(`Default branch: ${res.default_branch}`);
52
+ }
53
+ export async function list(flags) {
54
+ const config = requireConfig();
55
+ const orgId = requireOrg(flags, config, 'myapi git list [--org <id>]');
56
+ const repos = await sdkGit.listRepos(config.api_key, orgId);
57
+ if (flags.json) {
58
+ printJson(repos);
59
+ return;
60
+ }
61
+ printTable(repos.map(r => ({ name: r.name })), {
62
+ flags,
63
+ empty: 'No repositories yet. Create one with: myapi git create <name>',
64
+ });
65
+ }
66
+ export async function get(repo, flags) {
67
+ const config = requireConfig();
68
+ const orgId = requireOrg(flags, config, 'myapi git get <repo> [--org <id>]');
69
+ requireArg(repo, 'repo', 'myapi git get <repo>');
70
+ const r = await sdkGit.getRepo(config.api_key, orgId, repo);
71
+ if (flags.json) {
72
+ printJson(r);
73
+ return;
74
+ }
75
+ info(`Name: ${r.name}`);
76
+ info(`Default branch: ${r.default_branch}`);
77
+ info(`Branches: ${r.branches}`);
78
+ info(`Tags: ${r.tags}`);
79
+ }
80
+ export async function del(repo, flags) {
81
+ const config = requireConfig();
82
+ const orgId = requireOrg(flags, config, 'myapi git delete <repo> [--org <id>]');
83
+ requireArg(repo, 'repo', 'myapi git delete <repo>');
84
+ await sdkGit.deleteRepo(config.api_key, orgId, repo);
85
+ success(`Deleted repository ${repo}`);
86
+ }
87
+ // ── Refs / history ───────────────────────────────────────────────────────────
88
+ export async function refs(repo, flags) {
89
+ const config = requireConfig();
90
+ const orgId = requireOrg(flags, config, 'myapi git refs <repo> [--org <id>]');
91
+ requireArg(repo, 'repo', 'myapi git refs <repo>');
92
+ const r = await sdkGit.listRefs(config.api_key, orgId, repo);
93
+ if (flags.json) {
94
+ printJson(r);
95
+ return;
96
+ }
97
+ info(`HEAD: ${r.head}`);
98
+ info(`Branches (${r.branches.length}):`);
99
+ for (const b of r.branches)
100
+ info(` ${b.name} ${shortSha(b.sha)}`);
101
+ info(`Tags (${r.tags.length}):`);
102
+ for (const t of r.tags)
103
+ info(` ${t.name} ${shortSha(t.sha)}`);
104
+ }
105
+ export async function log(repo, flags) {
106
+ const config = requireConfig();
107
+ const orgId = requireOrg(flags, config, 'myapi git log <repo> [--ref <r>] [--limit <n>] [--org <id>]');
108
+ requireArg(repo, 'repo', 'myapi git log <repo>');
109
+ const commits = await sdkGit.listCommits(config.api_key, orgId, repo, {
110
+ ref: flags.ref,
111
+ limit: typeof flags.limit === 'number' ? flags.limit : undefined,
112
+ });
113
+ if (flags.json) {
114
+ printJson(commits);
115
+ return;
116
+ }
117
+ printTable(commits.map(c => ({
118
+ sha: shortSha(c.sha),
119
+ message: firstLine(c.message),
120
+ author: c.author,
121
+ when: c.when ? formatDate(c.when) : '',
122
+ })), { flags, empty: 'No commits.' });
123
+ }
124
+ export async function show(repo, sha, flags) {
125
+ const config = requireConfig();
126
+ const orgId = requireOrg(flags, config, 'myapi git show <repo> <sha> [--org <id>]');
127
+ requireArg(repo, 'repo', 'myapi git show <repo> <sha>');
128
+ requireArg(sha, 'sha', 'myapi git show <repo> <sha>');
129
+ const c = await sdkGit.getCommit(config.api_key, orgId, repo, sha);
130
+ if (flags.json) {
131
+ printJson(c);
132
+ return;
133
+ }
134
+ info(`Commit: ${c.sha}`);
135
+ info(`Author: ${c.author} <${c.email}>`);
136
+ info(`Date: ${c.when ? formatDate(c.when) : ''}`);
137
+ if (c.parents?.length)
138
+ info(`Parents: ${c.parents.map(shortSha).join(' ')}`);
139
+ info('');
140
+ info(c.message);
141
+ }
142
+ export async function tree(repo, ref, flags) {
143
+ const config = requireConfig();
144
+ const orgId = requireOrg(flags, config, 'myapi git tree <repo> <ref> [--path <p>] [--org <id>]');
145
+ requireArg(repo, 'repo', 'myapi git tree <repo> <ref>');
146
+ requireArg(ref, 'ref', 'myapi git tree <repo> <ref>');
147
+ const entries = await sdkGit.listTree(config.api_key, orgId, repo, ref, flags.path);
148
+ if (flags.json) {
149
+ printJson(entries);
150
+ return;
151
+ }
152
+ printTable(entries.map(e => ({
153
+ type: e.type,
154
+ mode: e.mode,
155
+ size: e.type === 'file' ? e.size : '',
156
+ path: e.path,
157
+ })), { flags, empty: 'Empty tree.' });
158
+ }
159
+ export async function blob(repo, ref, path, flags) {
160
+ const config = requireConfig();
161
+ const orgId = requireOrg(flags, config, 'myapi git blob <repo> <ref> <path> [--org <id>]');
162
+ requireArg(repo, 'repo', 'myapi git blob <repo> <ref> <path>');
163
+ requireArg(ref, 'ref', 'myapi git blob <repo> <ref> <path>');
164
+ requireArg(path, 'path', 'myapi git blob <repo> <ref> <path>');
165
+ const b = await sdkGit.readBlob(config.api_key, orgId, repo, ref, path);
166
+ if (flags.json) {
167
+ printJson(b);
168
+ return;
169
+ }
170
+ // Decode and print the file content raw — `git blob` is a `cat`.
171
+ process.stdout.write(Buffer.from(b.content_base64, 'base64').toString('utf-8'));
172
+ }
173
+ export async function diff(repo, flags) {
174
+ const config = requireConfig();
175
+ const orgId = requireOrg(flags, config, 'myapi git diff <repo> --base <ref> --head <ref> [--org <id>]');
176
+ requireArg(repo, 'repo', 'myapi git diff <repo> --base <ref> --head <ref>');
177
+ const base = flags.base;
178
+ const head = flags.head;
179
+ if (!base || !head)
180
+ error('Both --base <ref> and --head <ref> are required.\nUsage: myapi git diff <repo> --base <ref> --head <ref>');
181
+ const text = await sdkGit.getDiff(config.api_key, orgId, repo, base, head);
182
+ if (flags.json) {
183
+ printJson({ diff: text });
184
+ return;
185
+ }
186
+ process.stdout.write(text.endsWith('\n') || text === '' ? text : text + '\n');
187
+ }
188
+ // ── Writes ───────────────────────────────────────────────────────────────────
189
+ export async function commit(repo, flags) {
190
+ const config = requireConfig();
191
+ const orgId = requireOrg(flags, config, 'myapi git commit <repo> --branch <b> --message <m> --changes <json> [--org <id>]');
192
+ requireArg(repo, 'repo', 'myapi git commit <repo> --branch <b> --message <m> --changes <json>');
193
+ const branch = flags.branch;
194
+ if (!branch)
195
+ error('Missing --branch.\nUsage: myapi git commit <repo> --branch <b> --message <m> --changes <json>');
196
+ if (typeof flags.changes !== 'string') {
197
+ error('Missing --changes.\n--changes is a JSON array of file edits, e.g.\n --changes \'[{"path":"README.md","content":"# Hello"}]\'\nEach entry: {path, content | content_base64 | delete:true, mode?}.');
198
+ }
199
+ let changes;
200
+ try {
201
+ changes = JSON.parse(flags.changes);
202
+ if (!Array.isArray(changes))
203
+ throw new Error('not an array');
204
+ }
205
+ catch (e) {
206
+ error(`--changes is not valid JSON: ${e?.message ?? e}`);
207
+ }
208
+ const payload = {
209
+ branch,
210
+ message: flags.message || '',
211
+ changes: changes,
212
+ };
213
+ if (typeof flags.base === 'string')
214
+ payload.base = flags.base;
215
+ if (flags['author-name'] || flags['author-email']) {
216
+ payload.author = {
217
+ name: flags['author-name'] || '',
218
+ email: flags['author-email'] || '',
219
+ };
220
+ }
221
+ const res = await sdkGit.commit(config.api_key, orgId, repo, payload);
222
+ if (flags.json) {
223
+ printJson(res);
224
+ return;
225
+ }
226
+ success(`Committed ${shortSha(res.sha)} to ${res.branch}`);
227
+ info(`Tree: ${shortSha(res.tree)}`);
228
+ }
229
+ export async function createBranch(repo, name, flags) {
230
+ const config = requireConfig();
231
+ const orgId = requireOrg(flags, config, 'myapi git create-branch <repo> <name> --from <ref> [--org <id>]');
232
+ requireArg(repo, 'repo', 'myapi git create-branch <repo> <name> --from <ref>');
233
+ requireArg(name, 'name', 'myapi git create-branch <repo> <name> --from <ref>');
234
+ const from = flags.from;
235
+ if (!from)
236
+ error('Missing --from <ref>.\nUsage: myapi git create-branch <repo> <name> --from <ref>');
237
+ await sdkGit.createBranch(config.api_key, orgId, repo, name, from);
238
+ success(`Created branch ${name} (from ${from})`);
239
+ }
240
+ export async function deleteBranch(repo, branch, flags) {
241
+ const config = requireConfig();
242
+ const orgId = requireOrg(flags, config, 'myapi git delete-branch <repo> <branch> [--org <id>]');
243
+ requireArg(repo, 'repo', 'myapi git delete-branch <repo> <branch>');
244
+ requireArg(branch, 'branch', 'myapi git delete-branch <repo> <branch>');
245
+ await sdkGit.deleteBranch(config.api_key, orgId, repo, branch);
246
+ success(`Deleted branch ${branch}`);
247
+ }
248
+ export async function tag(repo, name, flags) {
249
+ const config = requireConfig();
250
+ const orgId = requireOrg(flags, config, 'myapi git tag <repo> <name> --ref <ref> [--org <id>]');
251
+ requireArg(repo, 'repo', 'myapi git tag <repo> <name> --ref <ref>');
252
+ requireArg(name, 'name', 'myapi git tag <repo> <name> --ref <ref>');
253
+ const ref = flags.ref;
254
+ if (!ref)
255
+ error('Missing --ref <ref>.\nUsage: myapi git tag <repo> <name> --ref <ref>');
256
+ await sdkGit.createTag(config.api_key, orgId, repo, name, ref);
257
+ success(`Created tag ${name} → ${ref}`);
258
+ }
259
+ export async function merge(repo, flags) {
260
+ const config = requireConfig();
261
+ const orgId = requireOrg(flags, config, 'myapi git merge <repo> --target <b> --source <b> [--org <id>]');
262
+ requireArg(repo, 'repo', 'myapi git merge <repo> --target <b> --source <b>');
263
+ const target = flags.target;
264
+ const source = flags.source;
265
+ if (!target || !source)
266
+ error('Both --target <branch> and --source <branch> are required.\nUsage: myapi git merge <repo> --target <b> --source <b>\n(Merge is fast-forward only.)');
267
+ const res = await sdkGit.merge(config.api_key, orgId, repo, target, source);
268
+ success(`Merged ${source} into ${target} → ${shortSha(res.sha)}`);
269
+ }
270
+ export async function repack(repo, flags) {
271
+ const config = requireConfig();
272
+ const orgId = requireOrg(flags, config, 'myapi git repack <repo> [--org <id>]');
273
+ requireArg(repo, 'repo', 'myapi git repack <repo>');
274
+ const res = await sdkGit.repack(config.api_key, orgId, repo);
275
+ if (flags.json) {
276
+ printJson(res);
277
+ return;
278
+ }
279
+ success(`Repacked ${repo}`);
280
+ info(`Packs: ${res.packs_before} → ${res.packs_after} · ${res.objects} objects`);
281
+ }
282
+ // ── Dispatcher ───────────────────────────────────────────────────────────────
283
+ const SUBCOMMAND_USAGE = {
284
+ 'create': 'myapi git create <name> [--default-branch <b>] [--org <id>]',
285
+ 'list': 'myapi git list [--org <id>] [--json]',
286
+ 'get': 'myapi git get <repo> [--org <id>] [--json]',
287
+ 'delete': 'myapi git delete <repo> [--org <id>]',
288
+ 'refs': 'myapi git refs <repo> [--org <id>] [--json]',
289
+ 'log': 'myapi git log <repo> [--ref <r>] [--limit <n>] [--org <id>] [--json]',
290
+ 'show': 'myapi git show <repo> <sha> [--org <id>] [--json]',
291
+ 'tree': 'myapi git tree <repo> <ref> [--path <p>] [--org <id>] [--json]',
292
+ 'blob': 'myapi git blob <repo> <ref> <path> [--org <id>]\n\nPrints the file content (decoded). --json gives {path, size, content_base64}.',
293
+ 'diff': 'myapi git diff <repo> --base <ref> --head <ref> [--org <id>]',
294
+ 'commit': `myapi git commit <repo> --branch <b> --message <m> --changes <json> [--base <ref>] [--author-name <n>] [--author-email <e>] [--org <id>]
295
+
296
+ --changes is a JSON array of file edits — each entry is
297
+ {path, content | content_base64 | delete:true, mode?}. Example:
298
+ myapi git commit my-repo --branch main --message "init" \\
299
+ --changes '[{"path":"README.md","content":"# Hello"}]'
300
+
301
+ --base is the expected current branch tip (optimistic concurrency);
302
+ omit it to create the branch, or pass it to guard against a stale write.`,
303
+ 'create-branch': 'myapi git create-branch <repo> <name> --from <ref> [--org <id>]',
304
+ 'delete-branch': 'myapi git delete-branch <repo> <branch> [--org <id>]',
305
+ 'tag': 'myapi git tag <repo> <name> --ref <ref> [--org <id>]',
306
+ 'merge': 'myapi git merge <repo> --target <branch> --source <branch> [--org <id>]\n\nFast-forward only.',
307
+ 'repack': 'myapi git repack <repo> [--org <id>]',
308
+ };
309
+ export async function run(subcommand, args, flags) {
310
+ if (!subcommand || (flags.help && !subcommand)) {
311
+ info(`Usage: myapi git <subcommand>
312
+
313
+ Hosted git repositories over HTTP — no local clone required.
314
+
315
+ Repositories:
316
+ create <name> Create a repository
317
+ list List repositories
318
+ get <repo> Show a repository's branch/tag counts
319
+ delete <repo> Delete a repository
320
+
321
+ History & content:
322
+ log <repo> List commits (--ref, --limit)
323
+ show <repo> <sha> Show a single commit
324
+ tree <repo> <ref> List a ref's file tree (--path)
325
+ blob <repo> <ref> <path> Print a file's content
326
+ diff <repo> Diff two refs (--base, --head)
327
+ refs <repo> List branches and tags
328
+
329
+ Writes:
330
+ commit <repo> Commit file changes (--branch, --message, --changes)
331
+ create-branch <repo> <name> Create a branch (--from <ref>)
332
+ delete-branch <repo> <branch> Delete a branch
333
+ tag <repo> <name> Create a tag (--ref <ref>)
334
+ merge <repo> Fast-forward merge (--target, --source)
335
+ repack <repo> Compact the repository's packfiles
336
+
337
+ All commands accept --org <id> (or set default: myapi config set-org <id>).`);
338
+ return;
339
+ }
340
+ if (flags.help) {
341
+ const usage = SUBCOMMAND_USAGE[subcommand];
342
+ if (usage)
343
+ info(`Usage: ${usage}`);
344
+ else
345
+ info(`Unknown subcommand: ${subcommand}. Run "myapi git --help" for the list.`);
346
+ return;
347
+ }
348
+ switch (subcommand) {
349
+ case 'create': return create(args[0], flags);
350
+ case 'list': return list(flags);
351
+ case 'get': return get(args[0], flags);
352
+ case 'delete': return del(args[0], flags);
353
+ case 'refs': return refs(args[0], flags);
354
+ case 'log': return log(args[0], flags);
355
+ case 'show': return show(args[0], args[1], flags);
356
+ case 'tree': return tree(args[0], args[1], flags);
357
+ case 'blob': return blob(args[0], args[1], args[2], flags);
358
+ case 'diff': return diff(args[0], flags);
359
+ case 'commit': return commit(args[0], flags);
360
+ case 'create-branch': return createBranch(args[0], args[1], flags);
361
+ case 'delete-branch': return deleteBranch(args[0], args[1], flags);
362
+ case 'tag': return tag(args[0], args[1], flags);
363
+ case 'merge': return merge(args[0], flags);
364
+ case 'repack': return repack(args[0], flags);
365
+ default: error(`Unknown subcommand: ${subcommand}. Run "myapi git --help" for a list of valid subcommands.`);
366
+ }
367
+ }
@@ -135,9 +135,12 @@ export async function identity(pixelId, flags) {
135
135
  const config = requireConfig();
136
136
  const orgId = flags.org || config.default_org;
137
137
  if (!orgId || !pixelId) {
138
- error("Missing required arguments.\nUsage: myapi pixel identity <pixel_id> --org <id>\n(Or set defaults via: myapi config set-org <id>)");
138
+ error("Missing required arguments.\nUsage: myapi pixel identity <pixel_id> --website <domain> [--org <id>]\n(Or set defaults via: myapi config set-org <id>)");
139
139
  }
140
- const res = await sdkPixel.getIdentity(config.api_key, orgId, pixelId);
140
+ // Identity resolution is scoped to a website the org owns — required.
141
+ if (!flags.website)
142
+ error("Missing required arg: --website <domain>. Identity resolution is scoped to a host the org owns.");
143
+ const res = await sdkPixel.getIdentity(config.api_key, orgId, pixelId, flags.website);
141
144
  printJson(res);
142
145
  }
143
146
  // ── Dispatcher ───────────────────────────────────────────────────────────────
@@ -146,7 +149,7 @@ const SUBCOMMAND_USAGE = {
146
149
  'visits': 'myapi pixel visits --website <domain> [--from <iso8601>] [--to <iso8601>] [--limit <num>] [--offset <num>] [--org <id>] [--json]',
147
150
  'events': 'myapi pixel events [--campaign-id <id>] [--domain <domain>] [--from <iso8601>] [--to <iso8601>] [--limit <num>] [--offset <num>] [--org <id>] [--json]',
148
151
  'audience': 'myapi pixel audience [--org <id>]',
149
- 'identity': 'myapi pixel identity <pixel_id> [--org <id>]',
152
+ 'identity': 'myapi pixel identity <pixel_id> --website <domain> [--org <id>]',
150
153
  };
151
154
  export async function run(subcommand, args, flags) {
152
155
  if (!subcommand || (flags.help && !subcommand)) {
@@ -0,0 +1 @@
1
+ export {};