@soku-ai/cli 0.1.0-alpha.17 → 0.1.0-alpha.18
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/dist/commands/auth.d.ts +1 -3
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +18 -3
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/automation.d.ts +46 -0
- package/dist/commands/automation.d.ts.map +1 -1
- package/dist/commands/automation.js +150 -0
- package/dist/commands/automation.js.map +1 -1
- package/dist/commands/changelog.d.ts +79 -0
- package/dist/commands/changelog.d.ts.map +1 -0
- package/dist/commands/changelog.js +123 -0
- package/dist/commands/changelog.js.map +1 -0
- package/dist/commands/context.d.ts +54 -0
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +362 -43
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/egress.d.ts +49 -1
- package/dist/commands/egress.d.ts.map +1 -1
- package/dist/commands/egress.js +222 -33
- package/dist/commands/egress.js.map +1 -1
- package/dist/commands/workspace.d.ts +13 -0
- package/dist/commands/workspace.d.ts.map +1 -1
- package/dist/commands/workspace.js +34 -7
- package/dist/commands/workspace.js.map +1 -1
- package/dist/generated/capabilities.json +4250 -1619
- package/dist/generated/changelog.json +1448 -0
- package/dist/http/client.d.ts +16 -0
- package/dist/http/client.d.ts.map +1 -1
- package/dist/http/client.js +25 -5
- package/dist/http/client.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/upload-journal.d.ts +46 -0
- package/dist/upload-journal.d.ts.map +1 -0
- package/dist/upload-journal.js +102 -0
- package/dist/upload-journal.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/skills/soku/SKILL.md +17 -2
- package/skills/soku/references/auth-workspace.md +27 -12
- package/skills/soku/references/egress-security.md +44 -0
- package/skills/soku/references/seo-automation-files.md +67 -3
- package/skills/soku/references/skills-updates.md +23 -0
package/dist/http/client.d.ts
CHANGED
|
@@ -6,6 +6,22 @@ interface RequestOptions {
|
|
|
6
6
|
/** Require the active org/brand headers (data endpoints). */
|
|
7
7
|
workspace?: boolean;
|
|
8
8
|
apiBase?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Throw {@link ApiError} instead of printing and exiting.
|
|
11
|
+
*
|
|
12
|
+
* The default is to exit, which is right for a one-shot command: the error
|
|
13
|
+
* envelope is the output. It is wrong inside a batch, where one file's
|
|
14
|
+
* transient 503 would take down a run of hundreds and leave the caller no
|
|
15
|
+
* chance to retry it. Batch callers set this and handle the error themselves.
|
|
16
|
+
*/
|
|
17
|
+
throwOnError?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** A failed request, raised only when the caller asked for `throwOnError`. */
|
|
20
|
+
export declare class ApiError extends Error {
|
|
21
|
+
readonly type: string;
|
|
22
|
+
readonly status: number;
|
|
23
|
+
readonly hint?: string | undefined;
|
|
24
|
+
constructor(type: string, message: string, status: number, hint?: string | undefined);
|
|
9
25
|
}
|
|
10
26
|
export declare function apiRequest<T = unknown>(path: string, opts?: RequestOptions): Promise<T>;
|
|
11
27
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/http/client.ts"],"names":[],"mappings":"AAAA;gFACgF;AAMhF,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,6DAA6D;IAC7D,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/http/client.ts"],"names":[],"mappings":"AAAA;gFACgF;AAMhF,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,6DAA6D;IAC7D,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED,8EAA8E;AAC9E,qBAAa,QAAS,SAAQ,KAAK;IAE/B,QAAQ,CAAC,IAAI,EAAE,MAAM;IAErB,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM;gBAHb,IAAI,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,EACN,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,MAAM,YAAA;CAKzB;AAED,wBAAsB,UAAU,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,CAAC,CAAC,CAwGjG"}
|
package/dist/http/client.js
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
import { clearToken, loadToken } from '../auth/store.js';
|
|
4
4
|
import { loadConfig, resolveApiBaseUrl } from '../config.js';
|
|
5
5
|
import { emitError, ExitCode } from '../output/envelope.js';
|
|
6
|
+
/** A failed request, raised only when the caller asked for `throwOnError`. */
|
|
7
|
+
export class ApiError extends Error {
|
|
8
|
+
type;
|
|
9
|
+
status;
|
|
10
|
+
hint;
|
|
11
|
+
constructor(type, message, status, hint) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.type = type;
|
|
14
|
+
this.status = status;
|
|
15
|
+
this.hint = hint;
|
|
16
|
+
this.name = 'ApiError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
6
19
|
export async function apiRequest(path, opts = {}) {
|
|
7
20
|
const token = await loadToken();
|
|
8
21
|
if (!token) {
|
|
@@ -28,6 +41,13 @@ export async function apiRequest(path, opts = {}) {
|
|
|
28
41
|
headers['X-Soku-Brand'] = brandId;
|
|
29
42
|
}
|
|
30
43
|
const base = resolveApiBaseUrl(opts.apiBase);
|
|
44
|
+
// Status 0 marks a failure that never reached the server, so a caller
|
|
45
|
+
// classifying retriability sees "no answer" rather than a fabricated code.
|
|
46
|
+
const fail = (type, message, status, code, hint) => {
|
|
47
|
+
if (opts.throwOnError)
|
|
48
|
+
throw new ApiError(type, message, status, hint);
|
|
49
|
+
return emitError(type, message, code, hint);
|
|
50
|
+
};
|
|
31
51
|
let res;
|
|
32
52
|
try {
|
|
33
53
|
res = await fetch(`${base}${path}`, {
|
|
@@ -41,7 +61,7 @@ export async function apiRequest(path, opts = {}) {
|
|
|
41
61
|
});
|
|
42
62
|
}
|
|
43
63
|
catch (err) {
|
|
44
|
-
return
|
|
64
|
+
return fail('network_error', `Could not reach ${base}: ${err.message}`, 0, ExitCode.RUNTIME, 'Behind a proxy? Set ALL_PROXY.');
|
|
45
65
|
}
|
|
46
66
|
const text = await res.text();
|
|
47
67
|
const parsed = text ? safeJson(text) : null;
|
|
@@ -51,16 +71,16 @@ export async function apiRequest(path, opts = {}) {
|
|
|
51
71
|
// cleanly instead of looping on a dead credential.
|
|
52
72
|
const code = parsed?.error ?? 'unauthorized';
|
|
53
73
|
await clearToken();
|
|
54
|
-
return
|
|
74
|
+
return fail('unauthorized', `Authentication failed (${code}).`, res.status, ExitCode.AUTH, 'Run `soku auth login`.');
|
|
55
75
|
}
|
|
56
76
|
if (res.status === 403) {
|
|
57
|
-
return
|
|
77
|
+
return fail('forbidden', describeError(parsed) ?? 'Access denied.', res.status, ExitCode.AUTH);
|
|
58
78
|
}
|
|
59
79
|
if (res.status === 404) {
|
|
60
|
-
return
|
|
80
|
+
return fail('not_found', describeError(parsed) ?? 'Not found.', res.status, ExitCode.NOT_FOUND);
|
|
61
81
|
}
|
|
62
82
|
if (res.status >= 400) {
|
|
63
|
-
return
|
|
83
|
+
return fail(describeCode(parsed) ?? 'request_failed', describeError(parsed) ?? `HTTP ${res.status}`, res.status, exitCodeForStatus(res.status), describeHint(parsed) ?? undefined);
|
|
64
84
|
}
|
|
65
85
|
return parsed;
|
|
66
86
|
}
|
package/dist/http/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/http/client.ts"],"names":[],"mappings":"AAAA;gFACgF;AAEhF,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAsB,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/http/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { registerAuthCommands } from './commands/auth.js';
|
|
|
6
6
|
import { registerAutomationCommands } from './commands/automation.js';
|
|
7
7
|
import { registerBrandCommands } from './commands/brand.js';
|
|
8
8
|
import { registerCallCommand } from './commands/call.js';
|
|
9
|
+
import { registerChangelogCommand } from './commands/changelog.js';
|
|
9
10
|
import { registerContextCommands } from './commands/context.js';
|
|
10
11
|
import { registerEgressCommands } from './commands/egress.js';
|
|
11
12
|
import { registerFilesCommands } from './commands/files.js';
|
|
@@ -41,6 +42,7 @@ registerContextCommands(program);
|
|
|
41
42
|
registerFilesCommands(program);
|
|
42
43
|
registerSkillCommand(program);
|
|
43
44
|
registerUpdateCommand(program);
|
|
45
|
+
registerChangelogCommand(program);
|
|
44
46
|
registerUpdateCheckCommand(program);
|
|
45
47
|
function commandNames(command) {
|
|
46
48
|
const names = new Set();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Durable record of one `soku context upload` run.
|
|
2
|
+
*
|
|
3
|
+
* A bulk upload of hundreds of files will lose some of them to transient
|
|
4
|
+
* failures no matter how many times it retries. Without a record of what the
|
|
5
|
+
* run intended to do, the only recovery is to re-run the whole command and
|
|
6
|
+
* hope, which is what forced manual batching and hand-checking of file counts.
|
|
7
|
+
* The journal makes a run resumable: it stores every planned file and the
|
|
8
|
+
* outcome of each one, so a later `--resume <run-id>` re-attempts exactly the
|
|
9
|
+
* files that never landed.
|
|
10
|
+
*
|
|
11
|
+
* Journals live under `~/.soku/uploads/` and are pruned by age, not by count,
|
|
12
|
+
* so a resume is still possible days later.
|
|
13
|
+
*/
|
|
14
|
+
export type UploadEntryStatus = 'pending' | 'done' | 'failed';
|
|
15
|
+
export interface UploadJournalEntry {
|
|
16
|
+
localPath: string;
|
|
17
|
+
targetDir: string;
|
|
18
|
+
filename: string;
|
|
19
|
+
status: UploadEntryStatus;
|
|
20
|
+
error?: string;
|
|
21
|
+
sizeBytes?: number;
|
|
22
|
+
contentType?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface UploadJournal {
|
|
25
|
+
runId: string;
|
|
26
|
+
createdAt: string;
|
|
27
|
+
updatedAt: string;
|
|
28
|
+
/** Workspace the run targeted; a resume into a different brand is refused. */
|
|
29
|
+
orgId: string | null;
|
|
30
|
+
brandId: string | null;
|
|
31
|
+
dir: string;
|
|
32
|
+
entries: UploadJournalEntry[];
|
|
33
|
+
}
|
|
34
|
+
/** Journals older than this are pruned on the next run. */
|
|
35
|
+
export declare const JOURNAL_RETENTION_DAYS = 14;
|
|
36
|
+
export declare function journalDir(): string;
|
|
37
|
+
export declare function newRunId(): string;
|
|
38
|
+
export declare function saveJournal(journal: UploadJournal): void;
|
|
39
|
+
export declare function loadJournal(runId: string): UploadJournal | null;
|
|
40
|
+
export declare function deleteJournal(runId: string): void;
|
|
41
|
+
/** Entries a resume should re-attempt: everything that is not confirmed done. */
|
|
42
|
+
export declare function pendingEntries(journal: UploadJournal): UploadJournalEntry[];
|
|
43
|
+
export declare function listJournals(): UploadJournal[];
|
|
44
|
+
/** Drop journals past the retention window so the directory cannot grow forever. */
|
|
45
|
+
export declare function pruneJournals(now?: number): number;
|
|
46
|
+
//# sourceMappingURL=upload-journal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-journal.d.ts","sourceRoot":"","sources":["../src/upload-journal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAQH,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAA;AAE7D,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,iBAAiB,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,8EAA8E;IAC9E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,kBAAkB,EAAE,CAAA;CAC9B;AAED,2DAA2D;AAC3D,eAAO,MAAM,sBAAsB,KAAK,CAAA;AAExC,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAMD,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAMxD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAM/D;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAMjD;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,kBAAkB,EAAE,CAE3E;AAED,wBAAgB,YAAY,IAAI,aAAa,EAAE,CAe9C;AAED,oFAAoF;AACpF,wBAAgB,aAAa,CAAC,GAAG,SAAa,GAAG,MAAM,CAsBtD"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/** Durable record of one `soku context upload` run.
|
|
2
|
+
*
|
|
3
|
+
* A bulk upload of hundreds of files will lose some of them to transient
|
|
4
|
+
* failures no matter how many times it retries. Without a record of what the
|
|
5
|
+
* run intended to do, the only recovery is to re-run the whole command and
|
|
6
|
+
* hope, which is what forced manual batching and hand-checking of file counts.
|
|
7
|
+
* The journal makes a run resumable: it stores every planned file and the
|
|
8
|
+
* outcome of each one, so a later `--resume <run-id>` re-attempts exactly the
|
|
9
|
+
* files that never landed.
|
|
10
|
+
*
|
|
11
|
+
* Journals live under `~/.soku/uploads/` and are pruned by age, not by count,
|
|
12
|
+
* so a resume is still possible days later.
|
|
13
|
+
*/
|
|
14
|
+
import { mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
15
|
+
import { join } from 'node:path';
|
|
16
|
+
import { randomUUID } from 'node:crypto';
|
|
17
|
+
import { configDir } from './config.js';
|
|
18
|
+
/** Journals older than this are pruned on the next run. */
|
|
19
|
+
export const JOURNAL_RETENTION_DAYS = 14;
|
|
20
|
+
export function journalDir() {
|
|
21
|
+
return join(configDir(), 'uploads');
|
|
22
|
+
}
|
|
23
|
+
function journalPath(runId) {
|
|
24
|
+
return join(journalDir(), `${runId}.json`);
|
|
25
|
+
}
|
|
26
|
+
export function newRunId() {
|
|
27
|
+
return randomUUID();
|
|
28
|
+
}
|
|
29
|
+
export function saveJournal(journal) {
|
|
30
|
+
const path = journalPath(journal.runId);
|
|
31
|
+
mkdirSync(journalDir(), { recursive: true });
|
|
32
|
+
writeFileSync(path, JSON.stringify({ ...journal, updatedAt: new Date().toISOString() }, null, 2), {
|
|
33
|
+
mode: 0o600,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export function loadJournal(runId) {
|
|
37
|
+
try {
|
|
38
|
+
return JSON.parse(readFileSync(journalPath(runId), 'utf8'));
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function deleteJournal(runId) {
|
|
45
|
+
try {
|
|
46
|
+
rmSync(journalPath(runId));
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Already gone; a finished run leaving no journal behind is the goal.
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Entries a resume should re-attempt: everything that is not confirmed done. */
|
|
53
|
+
export function pendingEntries(journal) {
|
|
54
|
+
return journal.entries.filter((entry) => entry.status !== 'done');
|
|
55
|
+
}
|
|
56
|
+
export function listJournals() {
|
|
57
|
+
let names;
|
|
58
|
+
try {
|
|
59
|
+
names = readdirSync(journalDir());
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
const journals = [];
|
|
65
|
+
for (const name of names) {
|
|
66
|
+
if (!name.endsWith('.json'))
|
|
67
|
+
continue;
|
|
68
|
+
const journal = loadJournal(name.slice(0, -'.json'.length));
|
|
69
|
+
if (journal)
|
|
70
|
+
journals.push(journal);
|
|
71
|
+
}
|
|
72
|
+
journals.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
73
|
+
return journals;
|
|
74
|
+
}
|
|
75
|
+
/** Drop journals past the retention window so the directory cannot grow forever. */
|
|
76
|
+
export function pruneJournals(now = Date.now()) {
|
|
77
|
+
const cutoff = now - JOURNAL_RETENTION_DAYS * 24 * 60 * 60 * 1000;
|
|
78
|
+
let names;
|
|
79
|
+
try {
|
|
80
|
+
names = readdirSync(journalDir());
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
let removed = 0;
|
|
86
|
+
for (const name of names) {
|
|
87
|
+
if (!name.endsWith('.json'))
|
|
88
|
+
continue;
|
|
89
|
+
const path = join(journalDir(), name);
|
|
90
|
+
try {
|
|
91
|
+
if (statSync(path).mtimeMs < cutoff) {
|
|
92
|
+
rmSync(path);
|
|
93
|
+
removed += 1;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// A journal that vanished mid-prune needs no further attention.
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return removed;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=upload-journal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-journal.js","sourceRoot":"","sources":["../src/upload-journal.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soku-ai/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.18",
|
|
4
4
|
"description": "Soku CLI — call Soku ads/GA4/PostHog data capabilities from any AI agent or shell.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "About Intelligence",
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
"registry": "https://registry.npmjs.org/"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
|
-
"build": "tsc && mkdir -p dist/generated && cp src/generated/capabilities.json
|
|
42
|
+
"build": "tsc && mkdir -p dist/generated && cp src/generated/capabilities.json src/generated/changelog.json dist/generated/",
|
|
43
43
|
"typecheck": "tsc --noEmit",
|
|
44
|
-
"test": "tsc -p tsconfig.test.json && find .test-build -name '*.test.js' -print | sort | xargs node --test",
|
|
44
|
+
"test": "tsc -p tsconfig.test.json && mkdir -p .test-build/generated && cp src/generated/capabilities.json src/generated/changelog.json .test-build/generated/ && find .test-build -name '*.test.js' -print | sort | xargs node --test && node --test scripts/*.test.mjs",
|
|
45
45
|
"clean": "rm -rf dist .test-build",
|
|
46
46
|
"postinstall": "node postinstall.cjs",
|
|
47
47
|
"prepublishOnly": "pnpm run clean && pnpm run build"
|
package/skills/soku/SKILL.md
CHANGED
|
@@ -9,7 +9,10 @@ description: >-
|
|
|
9
9
|
license: MIT
|
|
10
10
|
metadata:
|
|
11
11
|
author: About Intelligence
|
|
12
|
-
version: "0.
|
|
12
|
+
version: "0.5"
|
|
13
|
+
# CLI release this skill was written against. `soku changelog --since <that
|
|
14
|
+
# version>` lists what moved if the installed CLI is newer.
|
|
15
|
+
cliVersion: "0.1.0-alpha.18"
|
|
13
16
|
---
|
|
14
17
|
|
|
15
18
|
# Soku CLI
|
|
@@ -30,7 +33,7 @@ Read only the reference files needed for the user's task:
|
|
|
30
33
|
| Meta/Google/ChatGPT Ads writes, uploads, bulk create, review-gated approval | `references/ads-write.md` |
|
|
31
34
|
| SEO Hosting, automations, Context Hub files, temporary public file URLs | `references/seo-automation-files.md` |
|
|
32
35
|
| Third-party APIs through server-side credential injection; security rules | `references/egress-security.md` |
|
|
33
|
-
| Installing, updating, or removing Soku-managed local skills | `references/skills-updates.md` |
|
|
36
|
+
| Installing, updating, or removing Soku-managed local skills; finding out what an upgrade changed | `references/skills-updates.md` |
|
|
34
37
|
| 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. |
|
|
35
38
|
|
|
36
39
|
For an installed business skill such as `soku-ads-report`, read that skill too.
|
|
@@ -71,6 +74,18 @@ soku <namespace> <action> --help
|
|
|
71
74
|
|
|
72
75
|
## Non-Negotiable Rules
|
|
73
76
|
|
|
77
|
+
- **Confirm the target brand immediately before any write, and read it back
|
|
78
|
+
after.** Run `soku workspace status` in the same turn as the write — not
|
|
79
|
+
earlier in the session — and check the reported brand is the one the user
|
|
80
|
+
named (its `source` field tells you whether saved config or a `SOKU_BRAND_ID`
|
|
81
|
+
environment variable decided it, which is what you would have to change). The
|
|
82
|
+
CLI keeps whatever brand was selected last, and it does not follow the brand
|
|
83
|
+
the user is looking at in the web app, so a brand confirmed three turns ago
|
|
84
|
+
proves nothing about this write. After the write, read the object back
|
|
85
|
+
(`soku automation get`, `soku context list`, `soku seo-hosting pages list`)
|
|
86
|
+
and confirm it landed where you intended. A write into the wrong brand
|
|
87
|
+
succeeds silently and looks identical to a correct one; the read-back is the
|
|
88
|
+
only thing that tells them apart.
|
|
74
89
|
- Never print or persist the Soku access token.
|
|
75
90
|
- Never ask the user to paste third-party provider keys for covered providers.
|
|
76
91
|
- Do not fail just because an upstream provider key env var is unset. Use
|
|
@@ -30,9 +30,8 @@ with the exact `next` command returned by the CLI, prefixed the same way:
|
|
|
30
30
|
SOKU_NO_KEYCHAIN=1 soku auth login --device-code <device_code>
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
If the browser approval page shows no workspace options
|
|
34
|
-
|
|
35
|
-
selecting a workspace. Select a brand after login with
|
|
33
|
+
If the browser approval page shows no workspace options, the user can approve
|
|
34
|
+
directly without selecting a workspace. Select a brand after login with
|
|
36
35
|
`soku workspace use-brand`.
|
|
37
36
|
|
|
38
37
|
For CI or headless contexts, use `SOKU_TOKEN`; do not echo it.
|
|
@@ -47,6 +46,22 @@ still return a HITL review the user approves; that is the only gate left
|
|
|
47
46
|
(besides the active org/brand). The `--resource` flag and the `soku resources`
|
|
48
47
|
command have been removed from the CLI.
|
|
49
48
|
|
|
49
|
+
## What The Login Grants
|
|
50
|
+
|
|
51
|
+
The token is account-level, not brand-level. It reaches **every brand the signed-in
|
|
52
|
+
account can already access**, and the brand chosen on the approval page only sets
|
|
53
|
+
where the CLI starts.
|
|
54
|
+
|
|
55
|
+
Users regularly read that selection as the scope of the grant and are then
|
|
56
|
+
surprised to see other brands. If a user asks why they can see a brand they did
|
|
57
|
+
not authorize, say this plainly: the approval covered their whole account, and
|
|
58
|
+
the picker chose a starting point. `soku brand list` shows the full set.
|
|
59
|
+
|
|
60
|
+
The practical consequence is the opposite of a security concern and needs
|
|
61
|
+
stating too: **nothing stops a command from writing into the wrong brand.** The
|
|
62
|
+
active brand is sticky, does not follow the web app, and survives across
|
|
63
|
+
sessions. Confirm it in the same turn as any write.
|
|
64
|
+
|
|
50
65
|
## Workspace
|
|
51
66
|
|
|
52
67
|
Never infer Soku workspace state from the local shell directory.
|
|
@@ -61,6 +76,15 @@ If `resolve` is ambiguous, show the candidates and ask the user which exact
|
|
|
61
76
|
brand/org to use. For one-off scripts, `SOKU_ORG_ID` and `SOKU_BRAND_ID` can
|
|
62
77
|
override saved config.
|
|
63
78
|
|
|
79
|
+
`workspace status` resolves the same way requests do, so it reports the brand a
|
|
80
|
+
write would actually reach whichever source set it. Its `source` field says
|
|
81
|
+
which one won:
|
|
82
|
+
|
|
83
|
+
- `config` — the saved active brand. `soku workspace use-brand` changes it.
|
|
84
|
+
- `env` — `SOKU_ORG_ID` / `SOKU_BRAND_ID` are set and override the saved config.
|
|
85
|
+
In this case `use-brand` writes the config file but does **not** change where
|
|
86
|
+
writes land; change the environment variables instead.
|
|
87
|
+
|
|
64
88
|
Legacy commands still work, but prefer `workspace` for agent flows:
|
|
65
89
|
|
|
66
90
|
```bash
|
|
@@ -70,15 +94,6 @@ soku brand list
|
|
|
70
94
|
soku brand use <slug-or-id>
|
|
71
95
|
```
|
|
72
96
|
|
|
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
|
-
|
|
82
97
|
## Session State
|
|
83
98
|
|
|
84
99
|
```bash
|
|
@@ -14,6 +14,50 @@ soku egress -- curl -H "Authorization: Bearer $AHREFS_API_KEY" "https://api.ahre
|
|
|
14
14
|
`$AHREFS_API_KEY` may be unset locally. That is expected. The CLI strips empty
|
|
15
15
|
placeholder auth and the Soku API injects the real credential.
|
|
16
16
|
|
|
17
|
+
### Which curl flags are understood
|
|
18
|
+
|
|
19
|
+
`soku egress` forwards four things to the proxy — method, URL, headers, body —
|
|
20
|
+
so it parses the curl flags that decide those, and nothing else.
|
|
21
|
+
|
|
22
|
+
**Honored** (they change the request):
|
|
23
|
+
|
|
24
|
+
| Flag | Effect |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| `-X` / `--request` | HTTP method |
|
|
27
|
+
| `-I` / `--head` | method `HEAD` |
|
|
28
|
+
| `-H` / `--header` | request header |
|
|
29
|
+
| `-d` / `--data` / `--data-raw` / `--data-ascii` / `--data-binary` | body, sent verbatim |
|
|
30
|
+
| `--data-urlencode` | body, URL-encoded exactly as curl does |
|
|
31
|
+
| `-G` / `--get` | fold the accumulated data into the query string |
|
|
32
|
+
| `--url` | request URL |
|
|
33
|
+
| `-o` / `--output` | write the response body to this file |
|
|
34
|
+
|
|
35
|
+
Repeated data flags **accumulate**, joined with `&`, the way curl joins them.
|
|
36
|
+
`@file` reads a file and `@-` reads stdin, for both `-d` and `--data-urlencode`.
|
|
37
|
+
|
|
38
|
+
**Accepted and ignored**: `-s`, `-S`, `-i`, `-v`, `-k`, `-f`/`--fail`, `-L`,
|
|
39
|
+
`--compressed`, `-w`, `-m`/`--max-time`, `--connect-timeout`, `--retry`,
|
|
40
|
+
`--retry-delay`, `--retry-max-time`, `--retry-all-errors`, `--resolve`,
|
|
41
|
+
`--max-redirs`, `--limit-rate`, `-D`, and their long forms. These shape curl's
|
|
42
|
+
local behaviour — output noise, timeouts, retry policy — and cannot change the
|
|
43
|
+
request that is forwarded. Bundled short flags (`-sSL`) are understood.
|
|
44
|
+
|
|
45
|
+
**Anything else is an error.** A flag this list does not name stops the command
|
|
46
|
+
with a usage error naming the flag; the request is not sent. That is deliberate:
|
|
47
|
+
the previous behaviour skipped an unrecognised flag *and did not consume its
|
|
48
|
+
value*, so the value fell through and was dropped too. The request went out with
|
|
49
|
+
parameters missing and the third party answered about whatever it noticed first
|
|
50
|
+
— an error that pointed nowhere near the real cause. If a skill needs a flag
|
|
51
|
+
that is not listed, rewrite the request without it (inline the query in the URL,
|
|
52
|
+
move a `--form` upload to a body) rather than expecting it to be ignored.
|
|
53
|
+
|
|
54
|
+
### Encoding matches curl exactly
|
|
55
|
+
|
|
56
|
+
`--data-urlencode` is form encoding: a space becomes `+` (not `%20`) and
|
|
57
|
+
percent-escapes use lowercase hex (`%2c`, not `%2C`). The CLI reproduces this
|
|
58
|
+
byte for byte, so prefixing an existing curl does not change what the third
|
|
59
|
+
party receives.
|
|
60
|
+
|
|
17
61
|
List covered hosts:
|
|
18
62
|
|
|
19
63
|
```bash
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
# SEO Hosting, Automations, And Files
|
|
2
2
|
|
|
3
|
-
These commands
|
|
3
|
+
These commands all write to the **active** Soku workspace. Confirm the brand in
|
|
4
|
+
the same turn as the write, and read the result back afterwards:
|
|
4
5
|
|
|
5
6
|
```bash
|
|
6
7
|
soku workspace status
|
|
7
8
|
```
|
|
8
9
|
|
|
10
|
+
The CLI keeps whatever brand was selected last and does not follow the brand the
|
|
11
|
+
user has open in the web app. A write into the wrong brand succeeds and looks
|
|
12
|
+
exactly like a correct one, so the confirmation has to be immediate, not
|
|
13
|
+
something done earlier in the session.
|
|
14
|
+
|
|
9
15
|
## SEO Hosting Pages
|
|
10
16
|
|
|
11
17
|
SEO Hosting pages are complete HTML documents, not Markdown. They are addressed
|
|
@@ -57,7 +63,13 @@ risk.
|
|
|
57
63
|
|
|
58
64
|
```bash
|
|
59
65
|
soku automation list
|
|
66
|
+
soku automation get <automation_id>
|
|
60
67
|
soku automation create --name "Fast check" --prompt "Check account health" --cron "* * * * *" --timezone UTC
|
|
68
|
+
soku automation update <automation_id> --prompt "Check account health and budget"
|
|
69
|
+
soku automation pause <automation_id>
|
|
70
|
+
soku automation resume <automation_id>
|
|
71
|
+
soku automation delete <automation_id> --confirm
|
|
72
|
+
soku automation deps <automation_id>
|
|
61
73
|
soku automation trigger <automation_id>
|
|
62
74
|
soku automation runs <automation_id>
|
|
63
75
|
```
|
|
@@ -68,8 +80,31 @@ soku automation runs <automation_id>
|
|
|
68
80
|
- `--interval-seconds <seconds>`; at least 3600 and divisible by 60.
|
|
69
81
|
- `--once-at <iso>` for a one-time UTC instant.
|
|
70
82
|
|
|
71
|
-
`
|
|
72
|
-
|
|
83
|
+
`update` sends only the flags you pass; everything else keeps its stored value.
|
|
84
|
+
It takes the same schedule flags as `create` (at most one), plus `--name`,
|
|
85
|
+
`--prompt`, and `--status`. `--timezone` is only accepted together with
|
|
86
|
+
`--cron`, because the server rebuilds the schedule from a whole contract and a
|
|
87
|
+
lone timezone would be silently dropped.
|
|
88
|
+
|
|
89
|
+
**Do not rebuild an automation to change it.** `update` edits the existing row
|
|
90
|
+
and keeps its id, run history, and schedule version. Rebuilding loses all three,
|
|
91
|
+
and leaves the original still scheduled unless you also pause or delete it.
|
|
92
|
+
|
|
93
|
+
`pause` stops an automation and clears its next run; `resume` puts it back to
|
|
94
|
+
active and recomputes the next run. Both are `update --status` underneath.
|
|
95
|
+
|
|
96
|
+
`deps` reports whether the automation's saved dependencies still resolve:
|
|
97
|
+
|
|
98
|
+
- **attachments** are looked up for real, so a deleted or cross-brand file shows
|
|
99
|
+
as `missing` before the automation next fires.
|
|
100
|
+
- **context references** are classified, not verified. A reference marked
|
|
101
|
+
`brand-pinned` (ad account, campaign, ad set, ad, report) names a row inside
|
|
102
|
+
the current brand: copying the automation into another brand carries the id
|
|
103
|
+
across but not the thing it points at, so those must be re-picked there. A
|
|
104
|
+
`portable` reference (skill, integration) does not have that problem.
|
|
105
|
+
|
|
106
|
+
Run `deps` before migrating an automation between brands, and after any change
|
|
107
|
+
that may have deleted a referenced file.
|
|
73
108
|
|
|
74
109
|
## Context Hub
|
|
75
110
|
|
|
@@ -83,6 +118,35 @@ soku context rm research/brief.pdf
|
|
|
83
118
|
|
|
84
119
|
Paths are context-relative. Do not include a `context/` prefix.
|
|
85
120
|
|
|
121
|
+
### Bulk uploads
|
|
122
|
+
|
|
123
|
+
`upload` takes directories (recursing and preserving structure under `--dir`)
|
|
124
|
+
and runs files concurrently. For a large migration:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
soku context upload ./assets --dir assets --concurrency 8 --verify
|
|
128
|
+
soku context uploads # runs with unfinished files
|
|
129
|
+
soku context upload --resume <run_id> # finish one of them
|
|
130
|
+
soku context verify ./assets --dir assets # reconcile without uploading
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- Each file is retried on transient failures (no response, HTTP 408/429/5xx)
|
|
134
|
+
before the run gives up on it; `--retries <n>` changes the attempt count. A
|
|
135
|
+
permanent failure such as 403 is not retried.
|
|
136
|
+
- Every run records a resumable run id. If any file is still unfinished when the
|
|
137
|
+
run ends, the output carries `resume_command` — run it to re-upload only the
|
|
138
|
+
files that never landed. Finished runs leave no record behind.
|
|
139
|
+
- `--resume` refuses to run if the active brand is not the one the recorded run
|
|
140
|
+
targeted. Switch back with `soku workspace use-brand` rather than forcing it:
|
|
141
|
+
the files would otherwise land, in the wrong brand, and look successful.
|
|
142
|
+
- `--verify` (and the standalone `soku context verify`) reconciles against the
|
|
143
|
+
server by size **and** checksum. A file the server reports no checksum for is
|
|
144
|
+
reported as `unverified`, not `ok` — a missing hash is not proof of a good
|
|
145
|
+
upload. Both `upload --verify` and `verify` exit non-zero if anything is
|
|
146
|
+
missing, mismatched, or unverified, so a script can gate on them.
|
|
147
|
+
|
|
148
|
+
Do not hand-count files to check a migration. `verify` is the reconciliation.
|
|
149
|
+
|
|
86
150
|
## Temporary Public File URLs
|
|
87
151
|
|
|
88
152
|
```bash
|
|
@@ -87,3 +87,26 @@ soku skill remove soku
|
|
|
87
87
|
|
|
88
88
|
Removing the last Soku-managed skill removes the local `.soku-skills.json`
|
|
89
89
|
manifest.
|
|
90
|
+
|
|
91
|
+
## After Upgrading The CLI
|
|
92
|
+
|
|
93
|
+
An upgrade can add, change, or retire capabilities, which invalidates whatever
|
|
94
|
+
this session believed the CLI could do. Ask the CLI itself rather than guessing:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
soku changelog --since <the version you upgraded from> --summary
|
|
98
|
+
soku changelog --since <the version you upgraded from>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`--summary` gives counts per version; without it, each entry lists the actions
|
|
102
|
+
that were added or removed and, for a surviving action, which fields changed.
|
|
103
|
+
Output is the usual JSON envelope in a non-TTY context, so it can be parsed.
|
|
104
|
+
|
|
105
|
+
The changelog is bundled with the installed CLI, so it always describes the
|
|
106
|
+
binary that is running and needs no network call. It cannot speak for versions
|
|
107
|
+
older than its `historyStartsAt`; when `--since` reaches past that, the response
|
|
108
|
+
sets `truncated: true` and says so rather than implying nothing changed.
|
|
109
|
+
|
|
110
|
+
This skill's frontmatter records the CLI release it was written against under
|
|
111
|
+
`metadata.cliVersion`. If the installed CLI is newer, run the command above
|
|
112
|
+
before relying on details in these reference files.
|