@soku-ai/cli 0.1.0-alpha.13 → 0.1.0-alpha.15
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.
- package/LICENSE +21 -0
- package/README.md +241 -0
- package/dist/commands/ads.d.ts.map +1 -1
- package/dist/commands/ads.js +36 -1
- package/dist/commands/ads.js.map +1 -1
- package/dist/commands/auth.d.ts +13 -0
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +10 -1
- package/dist/commands/auth.js.map +1 -1
- package/dist/generated/capabilities.json +14901 -5000
- package/dist/skills/unzip.js +1 -1
- package/dist/skills/unzip.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +6 -7
- package/skills/soku/SKILL.md +15 -7
- package/skills/soku/references/ads-write.md +71 -6
- package/skills/soku/references/auth-workspace.md +28 -3
- package/skills/soku/references/data-capabilities.md +26 -4
- package/skills/soku/references/egress-security.md +4 -1
package/dist/skills/unzip.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* (stripped) root. Pure — returns a relpath→bytes map without touching disk, so
|
|
8
8
|
* it is unit-testable and the caller decides where to write. */
|
|
9
9
|
import { unzipSync } from 'fflate';
|
|
10
|
-
const ALLOWED_EXTENSIONS = new Set(['.md', '.json', '.txt', '.yaml', '.yml', '.csv']);
|
|
10
|
+
const ALLOWED_EXTENSIONS = new Set(['.md', '.py', '.json', '.txt', '.yaml', '.yml', '.csv']);
|
|
11
11
|
const MAX_FILE_COUNT = 100;
|
|
12
12
|
const MAX_SINGLE_FILE_BYTES = 10 * 1024 * 1024;
|
|
13
13
|
const MAX_TOTAL_BYTES = 50 * 1024 * 1024;
|
package/dist/skills/unzip.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unzip.js","sourceRoot":"","sources":["../../src/skills/unzip.ts"],"names":[],"mappings":"AAAA;;;;;;;gEAOgE;AAEhE,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAElC,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"unzip.js","sourceRoot":"","sources":["../../src/skills/unzip.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soku-ai/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.15",
|
|
4
4
|
"description": "Soku CLI — call Soku ads/GA4/PostHog data capabilities from any AI agent or shell.",
|
|
5
|
-
"license": "
|
|
6
|
-
"author": "
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "About Intelligence",
|
|
7
7
|
"homepage": "https://soku.ai/cli",
|
|
8
8
|
"bugs": {
|
|
9
|
-
"url": "https://github.com/About-Intelligence/
|
|
9
|
+
"url": "https://github.com/About-Intelligence/soku-cli/issues"
|
|
10
10
|
},
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
13
|
-
"url": "git+https://github.com/About-Intelligence/
|
|
14
|
-
"directory": "apps/cli"
|
|
13
|
+
"url": "git+https://github.com/About-Intelligence/soku-cli.git"
|
|
15
14
|
},
|
|
16
15
|
"keywords": [
|
|
17
16
|
"soku",
|
|
@@ -34,6 +33,7 @@
|
|
|
34
33
|
"engines": {
|
|
35
34
|
"node": ">=20"
|
|
36
35
|
},
|
|
36
|
+
"packageManager": "pnpm@10.28.0",
|
|
37
37
|
"publishConfig": {
|
|
38
38
|
"access": "public",
|
|
39
39
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -42,7 +42,6 @@
|
|
|
42
42
|
"build": "tsc && mkdir -p dist/generated && cp src/generated/capabilities.json dist/generated/capabilities.json",
|
|
43
43
|
"typecheck": "tsc --noEmit",
|
|
44
44
|
"test": "tsc -p tsconfig.test.json && find .test-build -name '*.test.js' -print | sort | xargs node --test",
|
|
45
|
-
"gen:capabilities": "uv run --project ../.. python ../../scripts/gen_cli_capabilities.py",
|
|
46
45
|
"clean": "rm -rf dist .test-build",
|
|
47
46
|
"postinstall": "node postinstall.cjs",
|
|
48
47
|
"prepublishOnly": "pnpm run clean && pnpm run build"
|
package/skills/soku/SKILL.md
CHANGED
|
@@ -3,11 +3,12 @@ name: soku
|
|
|
3
3
|
description: >-
|
|
4
4
|
Use when calling Soku CLI capabilities from a shell: auth, workspace
|
|
5
5
|
selection, ads/GA4/PostHog data reads, typed ads writes, SEO Hosting,
|
|
6
|
-
automations, Context Hub files,
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
automations, Context Hub files, migrating context or project files from
|
|
7
|
+
Claude, temporary file publishing, brand skills, third-party egress,
|
|
8
|
+
review-gated writes, skill installation, or CLI updates.
|
|
9
|
+
license: MIT
|
|
9
10
|
metadata:
|
|
10
|
-
author:
|
|
11
|
+
author: About Intelligence
|
|
11
12
|
version: "0.4"
|
|
12
13
|
---
|
|
13
14
|
|
|
@@ -26,10 +27,11 @@ Read only the reference files needed for the user's task:
|
|
|
26
27
|
| --- | --- |
|
|
27
28
|
| First-time setup, expired token, workspace selection, org/brand ambiguity | `references/auth-workspace.md` |
|
|
28
29
|
| Ads, GA4, or PostHog reads; raw `soku call`; command discovery | `references/data-capabilities.md` and `references/capability-flow.md` |
|
|
29
|
-
| Meta/Google Ads writes, uploads, bulk create, review-gated approval | `references/ads-write.md` |
|
|
30
|
+
| Meta/Google/ChatGPT Ads writes, uploads, bulk create, review-gated approval | `references/ads-write.md` |
|
|
30
31
|
| SEO Hosting, automations, Context Hub files, temporary public file URLs | `references/seo-automation-files.md` |
|
|
31
32
|
| Third-party APIs through server-side credential injection; security rules | `references/egress-security.md` |
|
|
32
33
|
| Installing, updating, or removing Soku-managed local skills | `references/skills-updates.md` |
|
|
34
|
+
| Migrate context, project files, or workspaces from Claude into Soku | Run `soku skill install migrate-from-claude`, then read the installed `soku-migrate-from-claude` skill. |
|
|
33
35
|
|
|
34
36
|
For an installed business skill such as `soku-ads-report`, read that skill too.
|
|
35
37
|
Business skills carry their own "Running this skill with the Soku CLI" section.
|
|
@@ -73,8 +75,14 @@ soku <namespace> <action> --help
|
|
|
73
75
|
- Never ask the user to paste third-party provider keys for covered providers.
|
|
74
76
|
- Do not fail just because an upstream provider key env var is unset. Use
|
|
75
77
|
`soku egress -- curl ...` for covered third-party APIs.
|
|
76
|
-
-
|
|
77
|
-
|
|
78
|
+
- A human must authorize every review-gated write — but don't force a
|
|
79
|
+
copy-paste. If your harness prompts for explicit human confirmation before
|
|
80
|
+
each shell command (e.g. Claude Code's permission prompt), you MAY run
|
|
81
|
+
`soku review approve <id>` yourself after showing the user the diff/summary;
|
|
82
|
+
that confirmation prompt is the human gate. Never allowlist or auto-approve
|
|
83
|
+
`soku review approve`/`deny`, and never approve a write the user has not seen.
|
|
84
|
+
If your harness runs commands without per-command human confirmation, do NOT
|
|
85
|
+
self-approve — surface the `review_id` for the user to run.
|
|
78
86
|
- Pass user values as separate argv elements. Do not build a shell command by
|
|
79
87
|
string-concatenating untrusted values.
|
|
80
88
|
- Do not scan local repo files, `AGENTS.md`, or `context/` folders for Soku
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Ads Writes
|
|
2
2
|
|
|
3
|
-
Meta and
|
|
4
|
-
delivery-changing writes are review-gated: the command creates a
|
|
5
|
-
and does not execute until a human approves.
|
|
3
|
+
Meta, Google, and ChatGPT Ads write commands use typed CLI surfaces where
|
|
4
|
+
available. Most delivery-changing writes are review-gated: the command creates a
|
|
5
|
+
pending review and does not execute until a human approves.
|
|
6
6
|
|
|
7
7
|
## Prerequisites
|
|
8
8
|
|
|
@@ -19,10 +19,25 @@ delivery-changing write still returns a pending review for a human to approve.
|
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
21
|
soku ads meta account pages --account-id <meta_account_id>
|
|
22
|
+
soku ads meta account instagram --account-id <meta_account_id>
|
|
22
23
|
soku ads meta campaign get --account-id <meta_account_id> --campaign-id <campaign_id>
|
|
23
24
|
soku ads meta ad get --account-id <meta_account_id> --ad-id <ad_id>
|
|
24
25
|
```
|
|
25
26
|
|
|
27
|
+
### Instagram identity (required for IG placements)
|
|
28
|
+
|
|
29
|
+
Before creating any creative that runs on Instagram, resolve the
|
|
30
|
+
**ad-account-connected** IG identity. The public IG `@handle` or the Facebook
|
|
31
|
+
Page id is rejected by the ads API — you must use the id returned by:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
soku ads meta account instagram --account-id <meta_account_id>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Pass that `data[].id` as `instagram_user_id` (e.g. `-p instagram_user_id=<id>`)
|
|
38
|
+
when building the creative. An empty result means no IG account is connected to
|
|
39
|
+
the ad account — connect it in Business Manager first.
|
|
40
|
+
|
|
26
41
|
## Meta Assets
|
|
27
42
|
|
|
28
43
|
Image upload mutates the Meta asset library but does not change delivery, so it
|
|
@@ -82,6 +97,23 @@ soku ads meta ad create \
|
|
|
82
97
|
--summary "Create paused Meta ad Hero image ad"
|
|
83
98
|
```
|
|
84
99
|
|
|
100
|
+
Dynamic creative (Advantage+ creative) uses `--asset-feed-spec` instead of a
|
|
101
|
+
single asset — Meta auto-combines the arrays. It is a primary media source, so
|
|
102
|
+
it is mutually exclusive with `--image-hash` / `--video-id` /
|
|
103
|
+
`--child-attachments`; the spec needs at least one of `images`/`videos` plus
|
|
104
|
+
`ad_formats`, and CTA / lead-form wiring goes inside the spec
|
|
105
|
+
(`call_to_action_types`), not as top-level flags. The ad set must be
|
|
106
|
+
dynamic-creative-enabled (`soku ads meta adset create ... -p is_dynamic_creative=true`).
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
soku ads meta creative create \
|
|
110
|
+
--account-id <meta_account_id> \
|
|
111
|
+
--name "Dynamic creative" \
|
|
112
|
+
--page-id <page_id> \
|
|
113
|
+
--asset-feed-spec '{"images":[{"hash":"<hash1>"},{"hash":"<hash2>"}],"bodies":[{"text":"Primary text A"},{"text":"Primary text B"}],"titles":[{"text":"Headline A"}],"link_urls":[{"website_url":"https://example.com"}],"call_to_action_types":["LEARN_MORE"],"ad_formats":["SINGLE_IMAGE"]}' \
|
|
114
|
+
--summary "Create Meta dynamic creative"
|
|
115
|
+
```
|
|
116
|
+
|
|
85
117
|
Status controls exist at delivery levels:
|
|
86
118
|
|
|
87
119
|
```bash
|
|
@@ -123,6 +155,35 @@ soku ads google keyword --help
|
|
|
123
155
|
The command path determines platform. Do not add `--platform`; the CLI injects
|
|
124
156
|
`platform=google`.
|
|
125
157
|
|
|
158
|
+
## ChatGPT Ads Writes
|
|
159
|
+
|
|
160
|
+
ChatGPT Ads uses the generic `ads` action surface. The platform object model is
|
|
161
|
+
ad unit first, campaign second:
|
|
162
|
+
|
|
163
|
+
1. Create one or more ad units with `ads/create_ad_unit`.
|
|
164
|
+
2. Create the campaign with `ads/create_campaign`, `platform=chatgpt_ads`, and a
|
|
165
|
+
non-empty `ad_unit_ids` list.
|
|
166
|
+
3. Keep new campaigns paused. The backend forces create to paused; do not submit
|
|
167
|
+
`update_campaign(status=active)` unless the user explicitly asks for
|
|
168
|
+
activation and approves that exact review.
|
|
169
|
+
|
|
170
|
+
Use `soku call` when a typed command is not obvious:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
soku call ads create_ad_unit \
|
|
174
|
+
--payload '{"platform":"chatgpt_ads","account_id":"<account_id>","platform_extras":{"description":"Ad unit description","landing_page":"https://example.com/?utm_source=chatgpt_ads","static_ad_text":"Primary text","static_cta":"Learn more"}}' \
|
|
175
|
+
--summary "Create paused ChatGPT Ads ad unit input"
|
|
176
|
+
|
|
177
|
+
soku call ads create_campaign \
|
|
178
|
+
--payload '{"platform":"chatgpt_ads","account_id":"<account_id>","name":"Launch Test","budget_daily_micros":300000000,"platform_extras":{"landing_page":"https://example.com/?utm_source=chatgpt_ads","campaign_objective":"clicks","ad_unit_ids":["<ad_unit_id>"]}}' \
|
|
179
|
+
--summary "Create paused ChatGPT Ads campaign Launch Test"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Available ChatGPT Ads write actions: `create_ad_unit`, `create_campaign`,
|
|
183
|
+
`generate_ad_units`, `add_campaign_ad_units`, `replace_campaign_ad_units`,
|
|
184
|
+
`update_campaign`, and `archive_ad_unit`. Treat `archive_ad_unit` as a toggle:
|
|
185
|
+
verify current state before using it.
|
|
186
|
+
|
|
126
187
|
## Review Gate
|
|
127
188
|
|
|
128
189
|
Review-gated commands return a review id:
|
|
@@ -132,6 +193,10 @@ soku review list
|
|
|
132
193
|
soku review show <review_id>
|
|
133
194
|
```
|
|
134
195
|
|
|
135
|
-
As an agent, show the review id and summary to the user
|
|
136
|
-
|
|
137
|
-
|
|
196
|
+
As an agent, always show the review id and summary to the user first — a human
|
|
197
|
+
must authorize the write. If your harness prompts for explicit human
|
|
198
|
+
confirmation before each shell command (e.g. Claude Code's permission prompt),
|
|
199
|
+
you MAY then run `soku review approve <id>` yourself: that prompt is the human
|
|
200
|
+
gate, so never allowlist or auto-approve it. If your harness auto-runs commands
|
|
201
|
+
without confirmation, do not self-approve — let the user run it. Approval is
|
|
202
|
+
single-use; failed approval is terminal, so create a fresh review for retry.
|
|
@@ -5,20 +5,36 @@ selected separately and sent on each workspace-scoped request.
|
|
|
5
5
|
|
|
6
6
|
## Agent Login: Non-Blocking Split Flow
|
|
7
7
|
|
|
8
|
+
In a shell/container agent environment, prefix every `soku auth login` call —
|
|
9
|
+
including the `--device-code` resume command below — with
|
|
10
|
+
`SOKU_NO_KEYCHAIN=1`. The token is only written on the resume/poll step, so if
|
|
11
|
+
each command runs in a fresh process (e.g. a new turn), an `export` on the
|
|
12
|
+
first call alone will not cover it. The CLI's OS-keychain lookup can hang
|
|
13
|
+
indefinitely with no output on boxes without a working keychain/D-Bus session
|
|
14
|
+
— that hang never times out or errors, so there is nothing to catch and retry
|
|
15
|
+
once it happens. The flag skips the OS keychain and stores the token in
|
|
16
|
+
`~/.soku/credentials.json` (0600) instead; this has no downside for an agent
|
|
17
|
+
session.
|
|
18
|
+
|
|
8
19
|
Do not block a turn waiting for browser approval. Start login with:
|
|
9
20
|
|
|
10
21
|
```bash
|
|
11
|
-
soku auth login --no-wait
|
|
22
|
+
SOKU_NO_KEYCHAIN=1 soku auth login --no-wait
|
|
12
23
|
```
|
|
13
24
|
|
|
14
25
|
Return the exact `verification_uri` and `user_code` to the user, then stop. Do
|
|
15
26
|
not edit, re-encode, or reconstruct the URL. After the user approves, resume
|
|
16
|
-
with the exact `next` command returned by the CLI:
|
|
27
|
+
with the exact `next` command returned by the CLI, prefixed the same way:
|
|
17
28
|
|
|
18
29
|
```bash
|
|
19
|
-
soku auth login --device-code <device_code>
|
|
30
|
+
SOKU_NO_KEYCHAIN=1 soku auth login --device-code <device_code>
|
|
20
31
|
```
|
|
21
32
|
|
|
33
|
+
If the browser approval page shows no workspace options (for example, a
|
|
34
|
+
platform admin with no org memberships), the user can approve directly without
|
|
35
|
+
selecting a workspace. Select a brand after login with
|
|
36
|
+
`soku workspace use-brand`.
|
|
37
|
+
|
|
22
38
|
For CI or headless contexts, use `SOKU_TOKEN`; do not echo it.
|
|
23
39
|
|
|
24
40
|
## Resources
|
|
@@ -54,6 +70,15 @@ soku brand list
|
|
|
54
70
|
soku brand use <slug-or-id>
|
|
55
71
|
```
|
|
56
72
|
|
|
73
|
+
## Platform Admins
|
|
74
|
+
|
|
75
|
+
`soku auth status` reports `is_platform_admin`, which is `true` only for an
|
|
76
|
+
active platform admin. An active platform admin can work across every active
|
|
77
|
+
org without holding an org membership: `soku workspace use-brand`,
|
|
78
|
+
`soku workspace resolve`, `soku org list`, and `soku brand list` cover the
|
|
79
|
+
full set of active orgs and brands. Everyone else stays scoped to the orgs
|
|
80
|
+
where they have a membership.
|
|
81
|
+
|
|
57
82
|
## Session State
|
|
58
83
|
|
|
59
84
|
```bash
|
|
@@ -43,13 +43,35 @@ soku ads query-single-dimension \
|
|
|
43
43
|
--date-end 2026-05-07
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
ChatGPT Ads is
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
For reporting, ChatGPT Ads is still cached-first. `query-multi-dimension` does
|
|
47
|
+
not support it (use `query-single-dimension` instead). Campaign/ad-unit writes
|
|
48
|
+
now exist as review-gated `ads` actions; use `ads-write.md` for the write flow.
|
|
49
49
|
|
|
50
50
|
## Google Ads GAQL Fallback
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
For common account, campaign, ad, keyword, search-term, and bidding-strategy
|
|
53
|
+
reports, prefer the predefined report command over ad-hoc GAQL. It selects a
|
|
54
|
+
stable set of columns and uses the last 30 days when dates are omitted:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
soku ads get-google-ads-report \
|
|
58
|
+
--platform google \
|
|
59
|
+
--account-id <account_id> \
|
|
60
|
+
--report-type campaign \
|
|
61
|
+
--start-date 2026-06-01 \
|
|
62
|
+
--end-date 2026-06-30
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Supported report types are `account`, `campaign`, `ad`, `keyword`,
|
|
66
|
+
`search_term`, and `bidding_strategy`.
|
|
67
|
+
|
|
68
|
+
Use GAQL only when cached actions cannot answer the request.
|
|
69
|
+
|
|
70
|
+
`get-resource-metadata` needs a native Google credential; accounts connected
|
|
71
|
+
through a proxy credential (Pipedream / Composio) fail with
|
|
72
|
+
`field_metadata_unavailable` (400). In that case skip field discovery and run
|
|
73
|
+
`gaql-search` directly — an unknown field fails with `gaql_invalid_query`
|
|
74
|
+
naming the offending field.
|
|
53
75
|
|
|
54
76
|
```bash
|
|
55
77
|
soku ads get-resource-metadata --platform google --account-id <account_id> --resource-name campaign
|
|
@@ -43,7 +43,10 @@ success envelope. Soku-level failures use the normal CLI error envelope.
|
|
|
43
43
|
|
|
44
44
|
- Never print the Soku access token.
|
|
45
45
|
- Prefer `SOKU_TOKEN` for CI and headless agents.
|
|
46
|
-
-
|
|
46
|
+
- Never approve a review-gated write the user has not seen, and never allowlist
|
|
47
|
+
or auto-approve `soku review approve`. Self-approving is allowed only when the
|
|
48
|
+
harness prompts for explicit human confirmation before each command (see the
|
|
49
|
+
review-gate rule in `references/ads-write.md`).
|
|
47
50
|
- Avoid literal secret argv values. For Cloudflare Worker setup use
|
|
48
51
|
`--cf-token-env` or `--cf-token-stdin`.
|
|
49
52
|
- Pass user-provided values as separate argv elements.
|