octwin-cli 0.8.1 → 0.8.3
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/CHANGELOG.md +720 -681
- package/README.md +4 -4
- package/dist/index.js +433 -346
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -448,12 +448,41 @@ function readManifestIdVersion(files) {
|
|
|
448
448
|
*/
|
|
449
449
|
const DEFAULT_URL_KEY = 'default_url';
|
|
450
450
|
function credsPath() { return join(homedir(), '.octwin', 'credentials.json'); }
|
|
451
|
+
/**
|
|
452
|
+
* The saved logins, or an empty map.
|
|
453
|
+
*
|
|
454
|
+
* ## A CORRUPT file is announced, not read as "never logged in"
|
|
455
|
+
*
|
|
456
|
+
* Both states produce `{}` and the advice attached to that answer — *run `octwin login`* — is
|
|
457
|
+
* right for the first and only accidentally right for the second: logging in again REWRITES
|
|
458
|
+
* the file, so it does clear the problem, while telling the author nothing about why a token
|
|
459
|
+
* they know they saved stopped being found. An interrupted write (a full disk, a killed
|
|
460
|
+
* process) is the likely cause and the one worth naming.
|
|
461
|
+
*
|
|
462
|
+
* Same three-state reasoning as [`kb-path.ts`](lib/kb-path.ts), reached the same way: absent
|
|
463
|
+
* and malformed are different facts and a reader that collapses them makes the caller guess.
|
|
464
|
+
* The warning goes to stderr so it cannot corrupt `--json` output on stdout.
|
|
465
|
+
*/
|
|
466
|
+
/** Once per process — `readCreds` has three call sites and one broken file is one problem. */
|
|
467
|
+
let credsWarned = false;
|
|
451
468
|
function readCreds() {
|
|
469
|
+
let raw;
|
|
452
470
|
try {
|
|
453
|
-
|
|
471
|
+
raw = readFileSync(credsPath(), 'utf8');
|
|
454
472
|
}
|
|
455
473
|
catch {
|
|
456
474
|
return {};
|
|
475
|
+
} // absent — the ordinary "not logged in"
|
|
476
|
+
try {
|
|
477
|
+
return JSON.parse(raw);
|
|
478
|
+
}
|
|
479
|
+
catch (e) {
|
|
480
|
+
if (!credsWarned) {
|
|
481
|
+
credsWarned = true;
|
|
482
|
+
console.error(`⚠ ${credsPath()} is not readable JSON (${e.message.split(String.fromCharCode(10))[0]}).`);
|
|
483
|
+
console.error(' Treating it as no saved login. `octwin login` will rewrite it.');
|
|
484
|
+
}
|
|
485
|
+
return {};
|
|
457
486
|
}
|
|
458
487
|
}
|
|
459
488
|
function writeCreds(map) {
|
|
@@ -559,7 +588,7 @@ async function outdatedNotice() {
|
|
|
559
588
|
function readLocalKb(packDir) {
|
|
560
589
|
const kbDir = findPlatformKbDir(packDir); // walks up — a repo-root pull covers every pack under it
|
|
561
590
|
if (!kbDir)
|
|
562
|
-
return null;
|
|
591
|
+
return null; // absent — nothing pulled, the ordinary case
|
|
563
592
|
try {
|
|
564
593
|
const idx = JSON.parse(readFileSync(join(kbDir, 'index.json'), 'utf8'));
|
|
565
594
|
return {
|
|
@@ -567,7 +596,19 @@ function readLocalKb(packDir) {
|
|
|
567
596
|
index: Array.isArray(idx.index) ? idx.index : [],
|
|
568
597
|
};
|
|
569
598
|
}
|
|
570
|
-
catch {
|
|
599
|
+
catch (e) {
|
|
600
|
+
/**
|
|
601
|
+
* A directory that EXISTS and will not parse is announced, never returned as null.
|
|
602
|
+
*
|
|
603
|
+
* Null means "nothing pulled" to all six callers, and the drift nudge, `platform-kb
|
|
604
|
+
* status/diff` and the feedback report's `content_hash` all read it that way. So a
|
|
605
|
+
* half-written `index.json` — an interrupted pull, the likeliest way this breaks —
|
|
606
|
+
* presented as "you have not pulled yet", and the author re-ran the same command that
|
|
607
|
+
* left it that way. `kb-path.ts` states this rule for the DIRECTORY lookup and gives the
|
|
608
|
+
* reasoning; the index read next to it kept collapsing anyway.
|
|
609
|
+
*/
|
|
610
|
+
console.error(`⚠ ${join(kbDir, 'index.json')} exists but could not be read (${e.message.split(String.fromCharCode(10))[0]}).`);
|
|
611
|
+
console.error(' Re-run `octwin platform-kb pull` — a previous pull was interrupted or the file is corrupt.');
|
|
571
612
|
return null;
|
|
572
613
|
}
|
|
573
614
|
}
|
|
@@ -892,17 +933,47 @@ async function cmdValidate(flags) {
|
|
|
892
933
|
const packDir = resolve(flags.dir ?? '.');
|
|
893
934
|
const { id, version, files, blobs } = localValidate(packDir); // offline structural gate first (fast, no server/token)
|
|
894
935
|
console.log(`✓ ${id}@${version} passes the offline structural check (${Object.keys(files).length} files, ${Object.keys(blobs).length} image(s))`);
|
|
895
|
-
/**
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
936
|
+
/**
|
|
937
|
+
* Every YAML file must PARSE — checked here, loudly, before anything reads one.
|
|
938
|
+
*
|
|
939
|
+
* This used to be a `try { … } catch { return [] }` inside `yamlDocs()`, on the stated
|
|
940
|
+
* ground that "a syntax error is the structural gate's to report". The structural gate
|
|
941
|
+
* (`validatePackBundle`) checks paths, extensions and traversal — it never parses YAML, so
|
|
942
|
+
* nothing reported it. The file was simply DROPPED from the list, every later check skipped
|
|
943
|
+
* it in silence, and `validate` printed all-green over a pack that could not be imported.
|
|
944
|
+
*
|
|
945
|
+
* Measured 2026-09-02: a duplicate `s_header:` key in a locale file passed `octwin validate`
|
|
946
|
+
* twice and was then refused by the platform's importer with `Map keys must be unique at
|
|
947
|
+
* line 24, column 3` — the SAME message this parser produces, from the same `yaml` version.
|
|
948
|
+
* The author's only clue was a red box in the console naming no file.
|
|
949
|
+
*
|
|
950
|
+
* Failing open is what made it dangerous: an unparseable file is not "no findings", it is
|
|
951
|
+
* "no idea", and those must never print the same. `parse()` already reports duplicate keys,
|
|
952
|
+
* bad indentation and unterminated strings — the ask was only to stop discarding it.
|
|
953
|
+
*/
|
|
954
|
+
const firstLine = (m) => m.split(String.fromCharCode(10))[0] ?? m;
|
|
955
|
+
const parsed = [];
|
|
956
|
+
const yamlErrors = [];
|
|
957
|
+
for (const [p, body] of Object.entries(files)) {
|
|
958
|
+
if (!/\.ya?ml$/i.test(p))
|
|
959
|
+
continue;
|
|
899
960
|
try {
|
|
900
|
-
|
|
961
|
+
parsed.push([p, parseYaml(body)]);
|
|
901
962
|
}
|
|
902
|
-
|
|
903
|
-
|
|
963
|
+
// First line only: the parser appends a source excerpt, which is useful in a terminal but
|
|
964
|
+
// turns one finding into five lines when several files fail at once.
|
|
965
|
+
catch (e) {
|
|
966
|
+
yamlErrors.push(`${p}: ${firstLine(e.message)}`);
|
|
904
967
|
}
|
|
905
|
-
}
|
|
968
|
+
}
|
|
969
|
+
if (yamlErrors.length > 0) {
|
|
970
|
+
for (const e of yamlErrors)
|
|
971
|
+
console.error(` ✗ ${e}`);
|
|
972
|
+
die(`YAML syntax (${yamlErrors.length} file${yamlErrors.length === 1 ? '' : 's'}) — the platform's importer refuses these too`);
|
|
973
|
+
}
|
|
974
|
+
console.log('✓ every YAML file parses (duplicate keys, indentation, unterminated strings)');
|
|
975
|
+
/** Every YAML file in the bundle, parsed once — all of them, since the gate above proved it. */
|
|
976
|
+
const yamlDocs = () => parsed;
|
|
906
977
|
// Checks that need the pulled KB. All of them DEGRADE when it is absent — the KB
|
|
907
978
|
// is a gitignored cache wiped by every pull, so failing hard would break a fresh
|
|
908
979
|
// clone before the author could act. But a skip is ANNOUNCED, and remembered:
|
|
@@ -1335,6 +1406,16 @@ async function readDeployProgress(body) {
|
|
|
1335
1406
|
const decoder = new TextDecoder();
|
|
1336
1407
|
let buf = '';
|
|
1337
1408
|
let terminal = null;
|
|
1409
|
+
/**
|
|
1410
|
+
* Frames whose `data:` would not parse.
|
|
1411
|
+
*
|
|
1412
|
+
* Skipping one is right — a partial frame or a shape this CLI version does not know is not
|
|
1413
|
+
* a reason to abort a deploy that is succeeding. Skipping ALL of them silently is not: if
|
|
1414
|
+
* the server's envelope changed, every frame is discarded, `terminal` stays null, and the
|
|
1415
|
+
* caller reports "the stream ended without a terminal event" — true, unhelpful, and
|
|
1416
|
+
* indistinguishable from a dropped connection. The count turns that into a diagnosis.
|
|
1417
|
+
*/
|
|
1418
|
+
let unparseableFrames = 0;
|
|
1338
1419
|
// Non-terminal frames with `status:'error'` are step failures the install
|
|
1339
1420
|
// SOFTENS to non-fatal (e.g. a demo-seed row) — the reconcile keeps going and
|
|
1340
1421
|
// still emits a `done`. We collect them so the deploy is NOT reported as a
|
|
@@ -1357,6 +1438,7 @@ async function readDeployProgress(body) {
|
|
|
1357
1438
|
ev = JSON.parse(dataLine.slice(5).trim());
|
|
1358
1439
|
}
|
|
1359
1440
|
catch {
|
|
1441
|
+
unparseableFrames++;
|
|
1360
1442
|
continue;
|
|
1361
1443
|
}
|
|
1362
1444
|
if (ev.stage === 'done' || ev.stage === 'error') {
|
|
@@ -1371,6 +1453,11 @@ async function readDeployProgress(body) {
|
|
|
1371
1453
|
}
|
|
1372
1454
|
}
|
|
1373
1455
|
}
|
|
1456
|
+
// Named only when it MATTERS: no terminal frame arrived and frames were discarded. Printing
|
|
1457
|
+
// it on a healthy deploy would be noise, and noise is how a real signal stops being read.
|
|
1458
|
+
if (terminal === null && unparseableFrames > 0) {
|
|
1459
|
+
console.error(`⚠ ${unparseableFrames} progress frame(s) could not be parsed — this CLI may be older than the platform. Try \`npm i -g octwin-cli@latest\`.`);
|
|
1460
|
+
}
|
|
1374
1461
|
return { terminal, stepErrors };
|
|
1375
1462
|
}
|
|
1376
1463
|
/** What a `--request-listing` / `--withdraw-listing` deploy says it is doing, for the header line. */
|
|
@@ -1509,13 +1596,13 @@ async function cmdSeed(flags) {
|
|
|
1509
1596
|
const { terminal: final, stepErrors } = await readDeployProgress(res.body);
|
|
1510
1597
|
if (!final || final.stage === 'error')
|
|
1511
1598
|
die(`seed failed${final?.message ? `: ${final.message}` : ' (stream ended early)'}`);
|
|
1512
|
-
console.log(`
|
|
1599
|
+
console.log(`
|
|
1513
1600
|
✓ ${final.message ?? 'seed complete'}`);
|
|
1514
1601
|
printSeedCounts(final.result?.seeded);
|
|
1515
1602
|
if (stepErrors.length) {
|
|
1516
1603
|
// A kind failed but the rest ran — the reconcile softens each step. Say which,
|
|
1517
1604
|
// and exit non-zero so a scripted `seed && chat` doesn't read as clean.
|
|
1518
|
-
console.error(`
|
|
1605
|
+
console.error(`
|
|
1519
1606
|
⚠ ${stepErrors.length} step${stepErrors.length === 1 ? '' : 's'} failed — data may be incomplete:`);
|
|
1520
1607
|
for (const e of stepErrors)
|
|
1521
1608
|
console.error(` • ${e}`);
|
|
@@ -4830,371 +4917,371 @@ async function cmdUsage(flags) {
|
|
|
4830
4917
|
console.log('\nThis is MODEL spend. WhatsApp/Meta message billing is operator-only — not reachable by an API token.');
|
|
4831
4918
|
}
|
|
4832
4919
|
function help() {
|
|
4833
|
-
console.log(`octwin ${VERSION} — Octwin external-pack developer CLI (by CEQUENS)
|
|
4834
|
-
|
|
4835
|
-
octwin --version # print the CLI version (+ any upgrade notice)
|
|
4836
|
-
octwin init <dir> [--id my-pack] [--description "..."] [--display-name "..."]
|
|
4837
|
-
octwin validate [--dir .] [--remote] [--require-kb] # --remote runs the platform's FULL schema check + lint (all errors at once)
|
|
4838
|
-
octwin login --url <platformUrl> --token oct_… # a deploy token from the console
|
|
4839
|
-
octwin whoami [--url <url>] [--tenant <slug>] # verify the token works
|
|
4840
|
-
octwin projects [--archived] [--json] # the --project slugs this token can name
|
|
4841
|
-
octwin deploy [--dir .] [--url <url>] [--tenant <slug>] [--project <slug>] [--token <t>] [--seed]
|
|
4842
|
-
[--request-listing | --withdraw-listing] # public marketplace — opt-in, see: octwin help deploy
|
|
4843
|
-
octwin status [<packId>] [--dir .] [--url <url>] [--tenant <slug>] [--project <slug>] [--token <t>]
|
|
4844
|
-
octwin pull <packId> [--dir <out>] [--version <v>] [--force] # write a DEPLOYED pack's source back to disk (the inverse of deploy)
|
|
4845
|
-
octwin records [entity] [id] # inspect the pack's XRM data (needs a records:read token)
|
|
4846
|
-
octwin work [recordId] [--queues] [--json] # inspect the work inbox (worked records) + timelines
|
|
4847
|
-
octwin logs [conversationId] [--as <handle>] [--json] # list conversations / show one's event timeline
|
|
4848
|
-
octwin chat "message" [--as <handle>] [--tap <tap-id>] [--media <file|id>] [--json] # drive a turn (+ send media) + print every render
|
|
4849
|
-
octwin media generate "<prompt>" [--out <file.png>] [--json] # AI-generate an image → MEDIA- handle (needs media:generate scope)
|
|
4850
|
-
octwin agents [packId::agentId] [--prompt] [--json] # effective model/memory + WHICH layer won; --prompt = the resolved system prompt
|
|
4851
|
-
octwin orders [reference_id] [--status s] [--payment p] [--json] # the orders a conversation produced + money + payment state
|
|
4852
|
-
octwin analytics [entity] [--funnel|--overview|--milestones|--trends|--cost] [--stage <id>] # stage conversion for any pipelined entity
|
|
4853
|
-
octwin catalog [--readiness] [--json] # commerce products + stock + the WhatsApp catalog binding
|
|
4854
|
-
octwin scheduling [--slots <resourceRecordId>] [--from YYYY-MM-DD] [--days n] # engine state / computed slots
|
|
4855
|
-
octwin automation [campaigns] [--json] # the jobs your declarations produced + health, last result each
|
|
4856
|
-
octwin integrations [--json] # declared connections BESIDE what is configured (the silent-never-fires check)
|
|
4857
|
-
octwin integrations deliveries [<id>] | events # the outbound delivery log / inbound events
|
|
4858
|
-
octwin journeys [journeyId] [--funnel|--overview|--goals|--trends|--cost|--definition] [--stage <id>]
|
|
4859
|
-
octwin performance [--detail] [--json] # the project's business indicators (value/conversion/duration)
|
|
4860
|
-
octwin usage [--json] # model calls, tokens and cost (project if pinned, else workspace)
|
|
4861
|
-
octwin platform-kb [pull] [--if-stale|--check] [--dir .] [--url <url>] # no token needed
|
|
4862
|
-
octwin test [--dir .] # = validate --remote (the full platform check)
|
|
4863
|
-
octwin feedback [--dir .] # submit this pack's FEEDBACK.md to the platform team
|
|
4864
|
-
octwin memos [--all] [--json] # read the platform's replies + notices (a reply to your feedback lands here)
|
|
4865
|
-
|
|
4866
|
-
Writes — exercise the state your pack creates (each needs the matching :write scope):
|
|
4867
|
-
octwin records create <entity> --set field=value … # also: patch <id> --entity <e>, stage <id> --to <s>, note <id> "…"
|
|
4868
|
-
octwin records tasks | task complete <taskId> [--outcome done|cancelled]
|
|
4869
|
-
octwin work assign <id> --to user:<uuid>|none | note <id> "…" | stage <id> --to <stage>
|
|
4870
|
-
octwin work decide <id> --action <a> [--param k=v] [--dry-run] # --dry-run previews, commits nothing
|
|
4871
|
-
octwin orders transition <ref> --to <status> | refund <ref> --force
|
|
4872
|
-
octwin catalog availability <sku> --to "in stock" | stock <sku> [--set-on-hand n]
|
|
4873
|
-
octwin scheduling rules --resource <id> | rule add|rm | exception add|rm
|
|
4874
|
-
octwin agents set <packId::agentId> [--model m] [--enable-tool t] [--disable-tool t]
|
|
4875
|
-
octwin automation run <jobId> | pause <jobId> | resume <jobId> | send <campaignId>
|
|
4876
|
-
octwin integrations test <key> # a LIVE call to the connection's health: operation
|
|
4877
|
-
octwin integrations retry|cancel|send-now <deliveryId>
|
|
4878
|
-
(octwin integrations preflight <key> needs only integrations:read — it makes no call)
|
|
4879
|
-
|
|
4880
|
-
Multi-turn: the platform keeps ONE open conversation per --as handle — consecutive
|
|
4881
|
-
\`octwin chat --as <h>\` calls continue the same conversation; press a rendered
|
|
4882
|
-
button/row with \`--tap "<tap-id>"\` (chat prints every tap id).
|
|
4883
|
-
Get a deploy token: console → your workspace → Settings → API tokens → Generate (tick records:read to inspect data).
|
|
4884
|
-
octwin platform-kb pull → writes the platform capability reference into .octwin/platform-kb/ (for the octwin-pack skill).
|
|
4885
|
-
Config (deploy): flags > env (PACK_PLATFORM_URL/PACK_TENANT/PACK_PROJECT/PACK_TOKEN) > saved login (\`octwin login\` sets the default target).
|
|
4920
|
+
console.log(`octwin ${VERSION} — Octwin external-pack developer CLI (by CEQUENS)
|
|
4921
|
+
|
|
4922
|
+
octwin --version # print the CLI version (+ any upgrade notice)
|
|
4923
|
+
octwin init <dir> [--id my-pack] [--description "..."] [--display-name "..."]
|
|
4924
|
+
octwin validate [--dir .] [--remote] [--require-kb] # --remote runs the platform's FULL schema check + lint (all errors at once)
|
|
4925
|
+
octwin login --url <platformUrl> --token oct_… # a deploy token from the console
|
|
4926
|
+
octwin whoami [--url <url>] [--tenant <slug>] # verify the token works
|
|
4927
|
+
octwin projects [--archived] [--json] # the --project slugs this token can name
|
|
4928
|
+
octwin deploy [--dir .] [--url <url>] [--tenant <slug>] [--project <slug>] [--token <t>] [--seed]
|
|
4929
|
+
[--request-listing | --withdraw-listing] # public marketplace — opt-in, see: octwin help deploy
|
|
4930
|
+
octwin status [<packId>] [--dir .] [--url <url>] [--tenant <slug>] [--project <slug>] [--token <t>]
|
|
4931
|
+
octwin pull <packId> [--dir <out>] [--version <v>] [--force] # write a DEPLOYED pack's source back to disk (the inverse of deploy)
|
|
4932
|
+
octwin records [entity] [id] # inspect the pack's XRM data (needs a records:read token)
|
|
4933
|
+
octwin work [recordId] [--queues] [--json] # inspect the work inbox (worked records) + timelines
|
|
4934
|
+
octwin logs [conversationId] [--as <handle>] [--json] # list conversations / show one's event timeline
|
|
4935
|
+
octwin chat "message" [--as <handle>] [--tap <tap-id>] [--media <file|id>] [--json] # drive a turn (+ send media) + print every render
|
|
4936
|
+
octwin media generate "<prompt>" [--out <file.png>] [--json] # AI-generate an image → MEDIA- handle (needs media:generate scope)
|
|
4937
|
+
octwin agents [packId::agentId] [--prompt] [--json] # effective model/memory + WHICH layer won; --prompt = the resolved system prompt
|
|
4938
|
+
octwin orders [reference_id] [--status s] [--payment p] [--json] # the orders a conversation produced + money + payment state
|
|
4939
|
+
octwin analytics [entity] [--funnel|--overview|--milestones|--trends|--cost] [--stage <id>] # stage conversion for any pipelined entity
|
|
4940
|
+
octwin catalog [--readiness] [--json] # commerce products + stock + the WhatsApp catalog binding
|
|
4941
|
+
octwin scheduling [--slots <resourceRecordId>] [--from YYYY-MM-DD] [--days n] # engine state / computed slots
|
|
4942
|
+
octwin automation [campaigns] [--json] # the jobs your declarations produced + health, last result each
|
|
4943
|
+
octwin integrations [--json] # declared connections BESIDE what is configured (the silent-never-fires check)
|
|
4944
|
+
octwin integrations deliveries [<id>] | events # the outbound delivery log / inbound events
|
|
4945
|
+
octwin journeys [journeyId] [--funnel|--overview|--goals|--trends|--cost|--definition] [--stage <id>]
|
|
4946
|
+
octwin performance [--detail] [--json] # the project's business indicators (value/conversion/duration)
|
|
4947
|
+
octwin usage [--json] # model calls, tokens and cost (project if pinned, else workspace)
|
|
4948
|
+
octwin platform-kb [pull] [--if-stale|--check] [--dir .] [--url <url>] # no token needed
|
|
4949
|
+
octwin test [--dir .] # = validate --remote (the full platform check)
|
|
4950
|
+
octwin feedback [--dir .] # submit this pack's FEEDBACK.md to the platform team
|
|
4951
|
+
octwin memos [--all] [--json] # read the platform's replies + notices (a reply to your feedback lands here)
|
|
4952
|
+
|
|
4953
|
+
Writes — exercise the state your pack creates (each needs the matching :write scope):
|
|
4954
|
+
octwin records create <entity> --set field=value … # also: patch <id> --entity <e>, stage <id> --to <s>, note <id> "…"
|
|
4955
|
+
octwin records tasks | task complete <taskId> [--outcome done|cancelled]
|
|
4956
|
+
octwin work assign <id> --to user:<uuid>|none | note <id> "…" | stage <id> --to <stage>
|
|
4957
|
+
octwin work decide <id> --action <a> [--param k=v] [--dry-run] # --dry-run previews, commits nothing
|
|
4958
|
+
octwin orders transition <ref> --to <status> | refund <ref> --force
|
|
4959
|
+
octwin catalog availability <sku> --to "in stock" | stock <sku> [--set-on-hand n]
|
|
4960
|
+
octwin scheduling rules --resource <id> | rule add|rm | exception add|rm
|
|
4961
|
+
octwin agents set <packId::agentId> [--model m] [--enable-tool t] [--disable-tool t]
|
|
4962
|
+
octwin automation run <jobId> | pause <jobId> | resume <jobId> | send <campaignId>
|
|
4963
|
+
octwin integrations test <key> # a LIVE call to the connection's health: operation
|
|
4964
|
+
octwin integrations retry|cancel|send-now <deliveryId>
|
|
4965
|
+
(octwin integrations preflight <key> needs only integrations:read — it makes no call)
|
|
4966
|
+
|
|
4967
|
+
Multi-turn: the platform keeps ONE open conversation per --as handle — consecutive
|
|
4968
|
+
\`octwin chat --as <h>\` calls continue the same conversation; press a rendered
|
|
4969
|
+
button/row with \`--tap "<tap-id>"\` (chat prints every tap id).
|
|
4970
|
+
Get a deploy token: console → your workspace → Settings → API tokens → Generate (tick records:read to inspect data).
|
|
4971
|
+
octwin platform-kb pull → writes the platform capability reference into .octwin/platform-kb/ (for the octwin-pack skill).
|
|
4972
|
+
Config (deploy): flags > env (PACK_PLATFORM_URL/PACK_TENANT/PACK_PROJECT/PACK_TOKEN) > saved login (\`octwin login\` sets the default target).
|
|
4886
4973
|
Per-command usage: octwin <command> --help`);
|
|
4887
4974
|
}
|
|
4888
4975
|
/** Per-subcommand usage — printed for `octwin <cmd> --help|-h` BEFORE any
|
|
4889
4976
|
* network/auth work (a --help that 401s is worse than no help at all). */
|
|
4890
4977
|
const COMMAND_HELP = {
|
|
4891
|
-
init: `octwin init <dir> [--id my-pack] [--description "..."] [--display-name "..."]
|
|
4978
|
+
init: `octwin init <dir> [--id my-pack] [--description "..."] [--display-name "..."]
|
|
4892
4979
|
Scaffold a pure-YAML starter pack into <dir>.`,
|
|
4893
|
-
validate: `octwin validate [--dir .] [--remote] [--require-kb] [--strict-primitives]
|
|
4894
|
-
Offline structural check, plus two checks driven by the pulled capability
|
|
4895
|
-
reference (render-intent fields, primitive arguments). Those two SKIP when the
|
|
4896
|
-
reference is missing — the run says so, and --require-kb turns the skip into a
|
|
4897
|
-
failure for CI. --remote additionally runs the platform's FULL manifest +
|
|
4898
|
-
flow-DSL validation and its flow lint (all errors at once) — same check as deploy.
|
|
4899
|
-
--strict-primitives (with --remote) additionally type-checks LITERAL args:
|
|
4900
|
-
values against each primitive's declared input schema; expression strings
|
|
4980
|
+
validate: `octwin validate [--dir .] [--remote] [--require-kb] [--strict-primitives]
|
|
4981
|
+
Offline structural check, plus two checks driven by the pulled capability
|
|
4982
|
+
reference (render-intent fields, primitive arguments). Those two SKIP when the
|
|
4983
|
+
reference is missing — the run says so, and --require-kb turns the skip into a
|
|
4984
|
+
failure for CI. --remote additionally runs the platform's FULL manifest +
|
|
4985
|
+
flow-DSL validation and its flow lint (all errors at once) — same check as deploy.
|
|
4986
|
+
--strict-primitives (with --remote) additionally type-checks LITERAL args:
|
|
4987
|
+
values against each primitive's declared input schema; expression strings
|
|
4901
4988
|
('$found.id', '{$t(…)}') are always exempt.`,
|
|
4902
|
-
login: `octwin login --url <platformUrl> --token oct_…
|
|
4903
|
-
Save a deploy token (console → Settings → API tokens) for that platform url,
|
|
4904
|
-
make that url the DEFAULT deploy target for every later command, and echo the
|
|
4989
|
+
login: `octwin login --url <platformUrl> --token oct_…
|
|
4990
|
+
Save a deploy token (console → Settings → API tokens) for that platform url,
|
|
4991
|
+
make that url the DEFAULT deploy target for every later command, and echo the
|
|
4905
4992
|
workspace + project pin + scopes the token reaches.`,
|
|
4906
|
-
whoami: `octwin whoami [--url <url>] [--tenant <slug>]
|
|
4993
|
+
whoami: `octwin whoami [--url <url>] [--tenant <slug>]
|
|
4907
4994
|
Verify the resolved token authenticates against the tenant.`,
|
|
4908
|
-
projects: `octwin projects [--archived] [--json]
|
|
4909
|
-
List the workspace's projects — the slugs every --project flag takes, with the
|
|
4910
|
-
plan's project cap. --archived includes archived ones. A pack:deploy token
|
|
4911
|
-
reaches this (it names a project in every other command).
|
|
4912
|
-
|
|
4913
|
-
octwin projects create "<name>" [--slug <slug>] [--pack <packId>]
|
|
4914
|
-
Create a project. The URL slug is derived from the name unless --slug pins one.
|
|
4915
|
-
--pack installs an ALREADY-published pack; the usual next step is instead
|
|
4916
|
-
\`octwin deploy --project <slug>\`, which publishes this working tree and installs it.
|
|
4917
|
-
|
|
4918
|
-
octwin projects rm <slug> [--yes]
|
|
4919
|
-
HARD delete — the project and everything cascading from it (conversations,
|
|
4920
|
-
contacts, records, installs). No undo, and not the same as archiving.
|
|
4921
|
-
WITHOUT --yes it only previews what would be destroyed, so the dry run is the
|
|
4922
|
-
default. Together these make a disposable end-to-end environment:
|
|
4923
|
-
octwin projects create "Scratch" && octwin deploy --project scratch --seed
|
|
4924
|
-
octwin chat "hi" --project scratch
|
|
4925
|
-
octwin projects rm scratch --yes
|
|
4995
|
+
projects: `octwin projects [--archived] [--json]
|
|
4996
|
+
List the workspace's projects — the slugs every --project flag takes, with the
|
|
4997
|
+
plan's project cap. --archived includes archived ones. A pack:deploy token
|
|
4998
|
+
reaches this (it names a project in every other command).
|
|
4999
|
+
|
|
5000
|
+
octwin projects create "<name>" [--slug <slug>] [--pack <packId>]
|
|
5001
|
+
Create a project. The URL slug is derived from the name unless --slug pins one.
|
|
5002
|
+
--pack installs an ALREADY-published pack; the usual next step is instead
|
|
5003
|
+
\`octwin deploy --project <slug>\`, which publishes this working tree and installs it.
|
|
5004
|
+
|
|
5005
|
+
octwin projects rm <slug> [--yes]
|
|
5006
|
+
HARD delete — the project and everything cascading from it (conversations,
|
|
5007
|
+
contacts, records, installs). No undo, and not the same as archiving.
|
|
5008
|
+
WITHOUT --yes it only previews what would be destroyed, so the dry run is the
|
|
5009
|
+
default. Together these make a disposable end-to-end environment:
|
|
5010
|
+
octwin projects create "Scratch" && octwin deploy --project scratch --seed
|
|
5011
|
+
octwin chat "hi" --project scratch
|
|
5012
|
+
octwin projects rm scratch --yes
|
|
4926
5013
|
Both verbs need the \`projects:write\` scope — a pack:deploy token does NOT confer it.`,
|
|
4927
|
-
deploy: `octwin deploy [--dir .] [--url <url>] [--tenant <slug>] [--project <slug>] [--token <t>] [--seed]
|
|
4928
|
-
[--request-listing | --withdraw-listing]
|
|
4929
|
-
Upload the pack bundle, validate server-side, install onto the project.
|
|
4930
|
-
--seed additionally applies the pack's demo seed (streams progress).
|
|
4931
|
-
|
|
4932
|
-
A plain deploy says NOTHING about the public marketplace — it is a test loop, so it
|
|
4933
|
-
neither asks for a listing nor gives one up. The marketplace flags are opt-in:
|
|
4934
|
-
|
|
4935
|
-
--request-listing ask an operator to review this pack for the public marketplace
|
|
4936
|
-
(the pre-signup storefront at /packs). Requires 'public: true'
|
|
4937
|
-
under 'listing:' in manifest.yaml — the manifest states that the
|
|
4938
|
-
pack is a product, the flag is you choosing to ask.
|
|
4939
|
-
--withdraw-listing retract the request, including an approved listing.
|
|
4940
|
-
|
|
4941
|
-
An approval covers the CONTENT it was made against, so a later deploy that changes the
|
|
5014
|
+
deploy: `octwin deploy [--dir .] [--url <url>] [--tenant <slug>] [--project <slug>] [--token <t>] [--seed]
|
|
5015
|
+
[--request-listing | --withdraw-listing]
|
|
5016
|
+
Upload the pack bundle, validate server-side, install onto the project.
|
|
5017
|
+
--seed additionally applies the pack's demo seed (streams progress).
|
|
5018
|
+
|
|
5019
|
+
A plain deploy says NOTHING about the public marketplace — it is a test loop, so it
|
|
5020
|
+
neither asks for a listing nor gives one up. The marketplace flags are opt-in:
|
|
5021
|
+
|
|
5022
|
+
--request-listing ask an operator to review this pack for the public marketplace
|
|
5023
|
+
(the pre-signup storefront at /packs). Requires 'public: true'
|
|
5024
|
+
under 'listing:' in manifest.yaml — the manifest states that the
|
|
5025
|
+
pack is a product, the flag is you choosing to ask.
|
|
5026
|
+
--withdraw-listing retract the request, including an approved listing.
|
|
5027
|
+
|
|
5028
|
+
An approval covers the CONTENT it was made against, so a later deploy that changes the
|
|
4942
5029
|
pack returns it to the review queue on its own — no flag needed, and the CLI says so.`,
|
|
4943
|
-
seed: `octwin seed [--pack <packId>]
|
|
4944
|
-
Apply the pack's demo/reference data to the project it is installed on, without
|
|
4945
|
-
redeploying: xrm \`demo:\` records + scheduling availability, the commerce catalog,
|
|
4946
|
-
and the demo operator topology. Reports what each kind produced.
|
|
4947
|
-
Idempotent and safe to re-run — records upsert, and existing media is REUSED rather
|
|
4948
|
-
than regenerated, so a second pass costs nothing. --pack is only needed when a
|
|
5030
|
+
seed: `octwin seed [--pack <packId>]
|
|
5031
|
+
Apply the pack's demo/reference data to the project it is installed on, without
|
|
5032
|
+
redeploying: xrm \`demo:\` records + scheduling availability, the commerce catalog,
|
|
5033
|
+
and the demo operator topology. Reports what each kind produced.
|
|
5034
|
+
Idempotent and safe to re-run — records upsert, and existing media is REUSED rather
|
|
5035
|
+
than regenerated, so a second pass costs nothing. --pack is only needed when a
|
|
4949
5036
|
project somehow runs more than one.`,
|
|
4950
|
-
status: `octwin status [<packId>] [--dir .] [--url <url>] [--tenant <slug>] [--project <slug>]
|
|
4951
|
-
Show installed vs live version + the flow list for this pack.
|
|
4952
|
-
The pack id is read from manifest.yaml and QUALIFIED with your workspace slug
|
|
4953
|
-
(a manifest declares a bare name; the owner is attached when you publish). Pass
|
|
4954
|
-
<packId> explicitly to skip that lookup — \`octwin agents\` and \`octwin projects\`
|
|
5037
|
+
status: `octwin status [<packId>] [--dir .] [--url <url>] [--tenant <slug>] [--project <slug>]
|
|
5038
|
+
Show installed vs live version + the flow list for this pack.
|
|
5039
|
+
The pack id is read from manifest.yaml and QUALIFIED with your workspace slug
|
|
5040
|
+
(a manifest declares a bare name; the owner is attached when you publish). Pass
|
|
5041
|
+
<packId> explicitly to skip that lookup — \`octwin agents\` and \`octwin projects\`
|
|
4955
5042
|
both print the qualified form.`,
|
|
4956
|
-
records: `octwin records [entity] [id] [--limit 50] [--offset n]
|
|
4957
|
-
Inspect the pack's XRM data. No args = list entities. Worked records (cases,
|
|
4958
|
-
tickets, anything routed to a queue) read best through \`octwin work\`.
|
|
4959
|
-
|
|
4960
|
-
WRITES (need \`records:write\`; every one is re-checked by RBAC on the record):
|
|
4961
|
-
octwin records create <entity> --set field=value [--set …] [--stage s] [--contact <id>]
|
|
4962
|
-
octwin records patch <recordId> --entity <entity> --set field=value
|
|
4963
|
-
octwin records stage <recordId> --to <stage> [--note "..."]
|
|
4964
|
-
octwin records note <recordId> "the note text"
|
|
4965
|
-
octwin records tasks # open follow-up tasks (\`tasks\` plan feature)
|
|
4966
|
-
octwin records task complete <taskId> [--outcome done|cancelled] [--note "..."]
|
|
4967
|
-
|
|
4968
|
-
--set coerces JSON scalars: \`--set rating=4.5\` sends a number, \`--set x=null\`
|
|
4969
|
-
sends null. Use --fields-json '{"a":{"b":1}}' for anything nested.
|
|
4970
|
-
\`patch\` needs --entity even though it has an id: the route resolves the field
|
|
4971
|
-
validator from it. A leading \`create/patch/stage/note/tasks/task\` is read as a
|
|
5043
|
+
records: `octwin records [entity] [id] [--limit 50] [--offset n]
|
|
5044
|
+
Inspect the pack's XRM data. No args = list entities. Worked records (cases,
|
|
5045
|
+
tickets, anything routed to a queue) read best through \`octwin work\`.
|
|
5046
|
+
|
|
5047
|
+
WRITES (need \`records:write\`; every one is re-checked by RBAC on the record):
|
|
5048
|
+
octwin records create <entity> --set field=value [--set …] [--stage s] [--contact <id>]
|
|
5049
|
+
octwin records patch <recordId> --entity <entity> --set field=value
|
|
5050
|
+
octwin records stage <recordId> --to <stage> [--note "..."]
|
|
5051
|
+
octwin records note <recordId> "the note text"
|
|
5052
|
+
octwin records tasks # open follow-up tasks (\`tasks\` plan feature)
|
|
5053
|
+
octwin records task complete <taskId> [--outcome done|cancelled] [--note "..."]
|
|
5054
|
+
|
|
5055
|
+
--set coerces JSON scalars: \`--set rating=4.5\` sends a number, \`--set x=null\`
|
|
5056
|
+
sends null. Use --fields-json '{"a":{"b":1}}' for anything nested.
|
|
5057
|
+
\`patch\` needs --entity even though it has an id: the route resolves the field
|
|
5058
|
+
validator from it. A leading \`create/patch/stage/note/tasks/task\` is read as a
|
|
4972
5059
|
VERB — to list an entity actually named one of those, use \`--entity <name>\`.`,
|
|
4973
|
-
work: `octwin work [recordId] [--queues] [--limit 50] [--offset n] [--json]
|
|
4974
|
-
Inspect the work inbox — every entity the pack declares worked (cases, orders
|
|
4975
|
-
needing review, applications, …): the inbox, one item + its timeline
|
|
4976
|
-
(+ applicable actions), or --queues for queue keys + open counts.
|
|
4977
|
-
|
|
4978
|
-
WRITES (need \`work:write\`; \`stage\` needs \`records:write\`):
|
|
4979
|
-
octwin work assign <recordId> --to user:<uuid>|team:<uuid>|none
|
|
4980
|
-
octwin work note <recordId> "the note text"
|
|
4981
|
-
octwin work stage <recordId> --to <stage> [--note "..."]
|
|
4982
|
-
octwin work decide <recordId> --action <action> [--param k=v] [--note "..."] [--dry-run]
|
|
4983
|
-
|
|
4984
|
-
\`decide\` applies one of the entity's declared operator actions — \`octwin work <id>\`
|
|
4985
|
-
lists them with their params. --dry-run previews the customer-facing copy and the
|
|
4986
|
-
resulting stage WITHOUT committing (that route needs only \`work:read\`).
|
|
5060
|
+
work: `octwin work [recordId] [--queues] [--limit 50] [--offset n] [--json]
|
|
5061
|
+
Inspect the work inbox — every entity the pack declares worked (cases, orders
|
|
5062
|
+
needing review, applications, …): the inbox, one item + its timeline
|
|
5063
|
+
(+ applicable actions), or --queues for queue keys + open counts.
|
|
5064
|
+
|
|
5065
|
+
WRITES (need \`work:write\`; \`stage\` needs \`records:write\`):
|
|
5066
|
+
octwin work assign <recordId> --to user:<uuid>|team:<uuid>|none
|
|
5067
|
+
octwin work note <recordId> "the note text"
|
|
5068
|
+
octwin work stage <recordId> --to <stage> [--note "..."]
|
|
5069
|
+
octwin work decide <recordId> --action <action> [--param k=v] [--note "..."] [--dry-run]
|
|
5070
|
+
|
|
5071
|
+
\`decide\` applies one of the entity's declared operator actions — \`octwin work <id>\`
|
|
5072
|
+
lists them with their params. --dry-run previews the customer-facing copy and the
|
|
5073
|
+
resulting stage WITHOUT committing (that route needs only \`work:read\`).
|
|
4987
5074
|
\`stage\` is the XRM records verb (one transition spelling platform-wide).`,
|
|
4988
|
-
logs: `octwin logs [conversationId] [--as <handle>] [--json]
|
|
4989
|
-
No id = recent conversations (handle, status, last activity; --as filters).
|
|
4990
|
-
With id = the full event timeline including what each turn rendered.
|
|
5075
|
+
logs: `octwin logs [conversationId] [--as <handle>] [--json]
|
|
5076
|
+
No id = recent conversations (handle, status, last activity; --as filters).
|
|
5077
|
+
With id = the full event timeline including what each turn rendered.
|
|
4991
5078
|
--json = raw events (verbatim payloads).`,
|
|
4992
|
-
pull: `octwin pull <packId> [--dir <out>] [--version <v>] [--force]
|
|
4993
|
-
Write a DEPLOYED pack's source back to disk — the inverse of deploy.
|
|
4994
|
-
A pack pushed with 'octwin deploy' lives on the platform as an artifact the
|
|
4995
|
-
runtime serves but nothing hands back, so its only source copy is the machine
|
|
4996
|
-
that pushed it. Pull it, fix it, redeploy it.
|
|
4997
|
-
Defaults to the version installed on the target project; --version overrides.
|
|
4998
|
-
--dir defaults to ./<packId>; a non-empty dir needs --force.
|
|
4999
|
-
The pulled dir redeploys where it came from — the target is your saved login.
|
|
5079
|
+
pull: `octwin pull <packId> [--dir <out>] [--version <v>] [--force]
|
|
5080
|
+
Write a DEPLOYED pack's source back to disk — the inverse of deploy.
|
|
5081
|
+
A pack pushed with 'octwin deploy' lives on the platform as an artifact the
|
|
5082
|
+
runtime serves but nothing hands back, so its only source copy is the machine
|
|
5083
|
+
that pushed it. Pull it, fix it, redeploy it.
|
|
5084
|
+
Defaults to the version installed on the target project; --version overrides.
|
|
5085
|
+
--dir defaults to ./<packId>; a non-empty dir needs --force.
|
|
5086
|
+
The pulled dir redeploys where it came from — the target is your saved login.
|
|
5000
5087
|
You may pull a pack your tenant OWNS (deployed); an operator token pulls any.`,
|
|
5001
|
-
chat: `octwin chat "message" [--as <handle>] [--tap <tap-id>] [--media <file|id>] [--json]
|
|
5002
|
-
octwin chat --script <file> [--as <handle>] [--json]
|
|
5003
|
-
Drive ONE turn through the dev web channel and print every render with its
|
|
5004
|
-
tap ids. Same --as handle = same conversation (multi-turn works).
|
|
5005
|
-
--tap presses a rendered button/list row instead of sending text.
|
|
5006
|
-
--media uploads a local file (or a media id from 'media generate --json') as
|
|
5007
|
-
an image/document/audio inbound — any "message" rides as its caption; feeds a
|
|
5008
|
-
running media-collect flow (e.g. activate-app).
|
|
5009
|
-
--json dumps the raw SSE envelopes for the turn.
|
|
5010
|
-
|
|
5011
|
-
--script drives a WHOLE conversation from a file, ONE TURN PER LINE, in one
|
|
5012
|
-
process over one connection — waiting for each turn to settle before sending
|
|
5013
|
-
the next. Use this for any multi-step flow: chaining shell invocations races
|
|
5014
|
-
the agent loop, because a turn ends on a quiet gap that can arrive while the
|
|
5015
|
-
server is still working (the symptom is placeholder-filled fields or a second
|
|
5016
|
-
workflow run). Blank lines and # comments are skipped:
|
|
5017
|
-
|
|
5018
|
-
# book an appointment end to end
|
|
5019
|
-
احجز موعد
|
|
5020
|
-
tap:t:invoke:book-appointment:doctor_id=D1
|
|
5021
|
-
media:./licence.jpg | here is my licence
|
|
5088
|
+
chat: `octwin chat "message" [--as <handle>] [--tap <tap-id>] [--media <file|id>] [--json]
|
|
5089
|
+
octwin chat --script <file> [--as <handle>] [--json]
|
|
5090
|
+
Drive ONE turn through the dev web channel and print every render with its
|
|
5091
|
+
tap ids. Same --as handle = same conversation (multi-turn works).
|
|
5092
|
+
--tap presses a rendered button/list row instead of sending text.
|
|
5093
|
+
--media uploads a local file (or a media id from 'media generate --json') as
|
|
5094
|
+
an image/document/audio inbound — any "message" rides as its caption; feeds a
|
|
5095
|
+
running media-collect flow (e.g. activate-app).
|
|
5096
|
+
--json dumps the raw SSE envelopes for the turn.
|
|
5097
|
+
|
|
5098
|
+
--script drives a WHOLE conversation from a file, ONE TURN PER LINE, in one
|
|
5099
|
+
process over one connection — waiting for each turn to settle before sending
|
|
5100
|
+
the next. Use this for any multi-step flow: chaining shell invocations races
|
|
5101
|
+
the agent loop, because a turn ends on a quiet gap that can arrive while the
|
|
5102
|
+
server is still working (the symptom is placeholder-filled fields or a second
|
|
5103
|
+
workflow run). Blank lines and # comments are skipped:
|
|
5104
|
+
|
|
5105
|
+
# book an appointment end to end
|
|
5106
|
+
احجز موعد
|
|
5107
|
+
tap:t:invoke:book-appointment:doctor_id=D1
|
|
5108
|
+
media:./licence.jpg | here is my licence
|
|
5022
5109
|
tap:t:resume:book-appointment:run_id=R1;_ctl_approved=true`,
|
|
5023
|
-
media: `octwin media generate "<prompt>" [--out <file.png>] [--json]
|
|
5024
|
-
AI-generate an image (needs a media:generate-scoped token), store it as a
|
|
5025
|
-
public asset, and print its MEDIA- handle + serve URL. --out downloads the
|
|
5026
|
-
bytes (WhatsApp renders only .png/.jpg); --json emits { media_id, url, mime,
|
|
5110
|
+
media: `octwin media generate "<prompt>" [--out <file.png>] [--json]
|
|
5111
|
+
AI-generate an image (needs a media:generate-scoped token), store it as a
|
|
5112
|
+
public asset, and print its MEDIA- handle + serve URL. --out downloads the
|
|
5113
|
+
bytes (WhatsApp renders only .png/.jpg); --json emits { media_id, url, mime,
|
|
5027
5114
|
bytes }. Pair with 'octwin chat --media' to drive media flows.`,
|
|
5028
|
-
agents: `octwin agents [packId::agentId] [--prompt] [--json]
|
|
5029
|
-
No args = the roster with each agent's EFFECTIVE model and which layer set it.
|
|
5030
|
-
With an agent = every governed setting (model / memory.last_messages /
|
|
5031
|
-
working_memory) plus the layer that won — an operator PLATFORM default can
|
|
5032
|
-
override what your manifest declares, and this is where you see that.
|
|
5033
|
-
--prompt = the exact system prompt the LLM sees for this project (pack
|
|
5034
|
-
instructions + platform protocol + any project overlay). Needs agents:read.
|
|
5035
|
-
The agent ref is the compound \`<packId>::<agentId>\` key or the override-row UUID.
|
|
5036
|
-
|
|
5037
|
-
WRITES (need \`agents:write\`):
|
|
5038
|
-
octwin agents set <ref> [--model <m>] [--enabled true|false] [--overlay "..."|none]
|
|
5039
|
-
[--enable-tool <toolId>] [--disable-tool <toolId>]
|
|
5040
|
-
|
|
5041
|
-
Only what you pass is changed. Tool flags read-modify-write \`config_json.tools\`
|
|
5042
|
-
so a sibling decision isn't dropped; absent = enabled. A workspace that hides model
|
|
5115
|
+
agents: `octwin agents [packId::agentId] [--prompt] [--json]
|
|
5116
|
+
No args = the roster with each agent's EFFECTIVE model and which layer set it.
|
|
5117
|
+
With an agent = every governed setting (model / memory.last_messages /
|
|
5118
|
+
working_memory) plus the layer that won — an operator PLATFORM default can
|
|
5119
|
+
override what your manifest declares, and this is where you see that.
|
|
5120
|
+
--prompt = the exact system prompt the LLM sees for this project (pack
|
|
5121
|
+
instructions + platform protocol + any project overlay). Needs agents:read.
|
|
5122
|
+
The agent ref is the compound \`<packId>::<agentId>\` key or the override-row UUID.
|
|
5123
|
+
|
|
5124
|
+
WRITES (need \`agents:write\`):
|
|
5125
|
+
octwin agents set <ref> [--model <m>] [--enabled true|false] [--overlay "..."|none]
|
|
5126
|
+
[--enable-tool <toolId>] [--disable-tool <toolId>]
|
|
5127
|
+
|
|
5128
|
+
Only what you pass is changed. Tool flags read-modify-write \`config_json.tools\`
|
|
5129
|
+
so a sibling decision isn't dropped; absent = enabled. A workspace that hides model
|
|
5043
5130
|
ids refuses --model with a 403 — the platform default governs there.`,
|
|
5044
|
-
orders: `octwin orders [reference_id] [--status s] [--payment p] [--limit 50] [--json]
|
|
5045
|
-
No args = the order list (#number, status/payment, total, contact). With a
|
|
5046
|
-
reference_id = line items, the subtotal/tax/shipping/discount/total breakdown,
|
|
5047
|
-
payment_ref, and the allowed status transitions. Needs orders:read + the
|
|
5048
|
-
\`orders\` plan feature. Note: the forward payment lifecycle is webhook-owned,
|
|
5049
|
-
so \`pending\` on a gateway-less workspace is expected, not a bug.
|
|
5050
|
-
|
|
5051
|
-
WRITES (need \`orders:write\`):
|
|
5052
|
-
octwin orders transition <reference_id> --to <status>
|
|
5053
|
-
octwin orders refund <reference_id> [--reason "..."] [--mark-returned] --force
|
|
5054
|
-
|
|
5055
|
-
Refund is irreversible and moves money, hence --force. The route answers 200 even
|
|
5056
|
-
when the GATEWAY refuses, so the CLI reads the gateway verdict and exits non-zero
|
|
5057
|
-
on a refusal rather than reporting a refund that never happened. Only a payment in
|
|
5131
|
+
orders: `octwin orders [reference_id] [--status s] [--payment p] [--limit 50] [--json]
|
|
5132
|
+
No args = the order list (#number, status/payment, total, contact). With a
|
|
5133
|
+
reference_id = line items, the subtotal/tax/shipping/discount/total breakdown,
|
|
5134
|
+
payment_ref, and the allowed status transitions. Needs orders:read + the
|
|
5135
|
+
\`orders\` plan feature. Note: the forward payment lifecycle is webhook-owned,
|
|
5136
|
+
so \`pending\` on a gateway-less workspace is expected, not a bug.
|
|
5137
|
+
|
|
5138
|
+
WRITES (need \`orders:write\`):
|
|
5139
|
+
octwin orders transition <reference_id> --to <status>
|
|
5140
|
+
octwin orders refund <reference_id> [--reason "..."] [--mark-returned] --force
|
|
5141
|
+
|
|
5142
|
+
Refund is irreversible and moves money, hence --force. The route answers 200 even
|
|
5143
|
+
when the GATEWAY refuses, so the CLI reads the gateway verdict and exits non-zero
|
|
5144
|
+
on a refusal rather than reporting a refund that never happened. Only a payment in
|
|
5058
5145
|
\`captured\` state can be refunded; \`payment_status\` is never settable directly.`,
|
|
5059
|
-
analytics: `octwin analytics [entity] [--funnel|--overview|--milestones|--trends|--cost] [--stage <id>] [--json]
|
|
5060
|
-
No args = the entities that carry a \`pipeline:\` (a funnel needs stages).
|
|
5061
|
-
With an entity = stage-by-stage conversion (default --funnel) over the last 30
|
|
5062
|
-
days. --stage <id> lists the records CURRENTLY at a stage (a live snapshot, not
|
|
5146
|
+
analytics: `octwin analytics [entity] [--funnel|--overview|--milestones|--trends|--cost] [--stage <id>] [--json]
|
|
5147
|
+
No args = the entities that carry a \`pipeline:\` (a funnel needs stages).
|
|
5148
|
+
With an entity = stage-by-stage conversion (default --funnel) over the last 30
|
|
5149
|
+
days. --stage <id> lists the records CURRENTLY at a stage (a live snapshot, not
|
|
5063
5150
|
range-filtered). Needs records:read + a \`view\` grant on \`record.<entity>\`.`,
|
|
5064
|
-
catalog: `octwin catalog [--readiness] [--json]
|
|
5065
|
-
The commerce \`product\` records + price, availability, stock (null = not
|
|
5066
|
-
inventory-tracked) and the WhatsApp catalog binding. --readiness runs the Meta
|
|
5067
|
-
Graph checklist (LIVE Graph calls; needs a bound access token). Needs
|
|
5068
|
-
catalog:read + the \`catalog\` plan feature.
|
|
5069
|
-
|
|
5070
|
-
WRITES (need \`catalog:write\`):
|
|
5071
|
-
octwin catalog availability <retailerId> --to "in stock"|"out of stock"|…
|
|
5072
|
-
octwin catalog stock <retailerId> [--set-on-hand <n>]
|
|
5073
|
-
|
|
5074
|
-
\`stock\` with no --set-on-hand READS it; \`null\` means the SKU is not
|
|
5075
|
-
inventory-tracked (always sellable), which is different from 0. Lowering on_hand
|
|
5076
|
-
below the units already reserved for open carts is refused. Creating/deleting
|
|
5151
|
+
catalog: `octwin catalog [--readiness] [--json]
|
|
5152
|
+
The commerce \`product\` records + price, availability, stock (null = not
|
|
5153
|
+
inventory-tracked) and the WhatsApp catalog binding. --readiness runs the Meta
|
|
5154
|
+
Graph checklist (LIVE Graph calls; needs a bound access token). Needs
|
|
5155
|
+
catalog:read + the \`catalog\` plan feature.
|
|
5156
|
+
|
|
5157
|
+
WRITES (need \`catalog:write\`):
|
|
5158
|
+
octwin catalog availability <retailerId> --to "in stock"|"out of stock"|…
|
|
5159
|
+
octwin catalog stock <retailerId> [--set-on-hand <n>]
|
|
5160
|
+
|
|
5161
|
+
\`stock\` with no --set-on-hand READS it; \`null\` means the SKU is not
|
|
5162
|
+
inventory-tracked (always sellable), which is different from 0. Lowering on_hand
|
|
5163
|
+
below the units already reserved for open carts is refused. Creating/deleting
|
|
5077
5164
|
products and the Meta catalog binding/sync stay in the console.`,
|
|
5078
|
-
scheduling: `octwin scheduling [--slots <resourceRecordId>] [--from YYYY-MM-DD] [--days n] [--json]
|
|
5079
|
-
No args = the engine state (bookable resource types, upcoming slots, booked
|
|
5080
|
-
seats). --slots <recordId> computes the slots for one bookable resource
|
|
5081
|
-
(occupancy included; --days is clamped to 1-31 server-side) — the way to verify
|
|
5082
|
-
the availability rules a \`deploy --seed\` created. Needs scheduling:read.
|
|
5083
|
-
|
|
5084
|
-
RULES (list needs scheduling:read; add/rm need scheduling:write):
|
|
5085
|
-
octwin scheduling rules --resource <resourceRecordId>
|
|
5086
|
-
octwin scheduling rule add --resource <id> --dow 1 --start 09:00 --end 17:00
|
|
5087
|
-
[--slot-minutes 30] [--capacity 1]
|
|
5088
|
-
octwin scheduling rule rm <ruleId>
|
|
5089
|
-
octwin scheduling exception add --resource <id> --date YYYY-MM-DD --kind closed|extra
|
|
5090
|
-
[--start 09:00 --end 13:00]
|
|
5091
|
-
octwin scheduling exception rm <exceptionId>
|
|
5092
|
-
|
|
5093
|
-
--dow is 0-6, 0 = Sunday. \`rules\` is how you find an id to remove, and
|
|
5165
|
+
scheduling: `octwin scheduling [--slots <resourceRecordId>] [--from YYYY-MM-DD] [--days n] [--json]
|
|
5166
|
+
No args = the engine state (bookable resource types, upcoming slots, booked
|
|
5167
|
+
seats). --slots <recordId> computes the slots for one bookable resource
|
|
5168
|
+
(occupancy included; --days is clamped to 1-31 server-side) — the way to verify
|
|
5169
|
+
the availability rules a \`deploy --seed\` created. Needs scheduling:read.
|
|
5170
|
+
|
|
5171
|
+
RULES (list needs scheduling:read; add/rm need scheduling:write):
|
|
5172
|
+
octwin scheduling rules --resource <resourceRecordId>
|
|
5173
|
+
octwin scheduling rule add --resource <id> --dow 1 --start 09:00 --end 17:00
|
|
5174
|
+
[--slot-minutes 30] [--capacity 1]
|
|
5175
|
+
octwin scheduling rule rm <ruleId>
|
|
5176
|
+
octwin scheduling exception add --resource <id> --date YYYY-MM-DD --kind closed|extra
|
|
5177
|
+
[--start 09:00 --end 13:00]
|
|
5178
|
+
octwin scheduling exception rm <exceptionId>
|
|
5179
|
+
|
|
5180
|
+
--dow is 0-6, 0 = Sunday. \`rules\` is how you find an id to remove, and
|
|
5094
5181
|
\`--slots\` is how you check what a rule actually produces.`,
|
|
5095
|
-
automation: `octwin automation [campaigns] [--limit n] [--offset n] [--json]
|
|
5096
|
-
No args = every job the pack's automation declaration produced, with its status,
|
|
5097
|
-
interval and LAST RESULT (matched / acted / errors), under a health line whose
|
|
5098
|
-
counts come from SQL rather than from filtering the page — the job list is capped
|
|
5099
|
-
server-side, so a client-side count would depend on the cap. Needs automation:read.
|
|
5100
|
-
|
|
5101
|
-
Jobs are DERIVED from declarations. There is no \`create\`: no automation block in
|
|
5102
|
-
the pack means no jobs, and \`octwin deploy\` is what installs them.
|
|
5103
|
-
|
|
5104
|
-
WRITES (automation:write):
|
|
5105
|
-
octwin automation run <jobId> # run once, now — prints matched/acted/errors
|
|
5106
|
-
octwin automation pause|resume <jobId>
|
|
5107
|
-
octwin automation send <campaignId> # enqueue a campaign; enqueued != delivered
|
|
5108
|
-
|
|
5109
|
-
<jobId> is the \`key\` the list shows (its uuid works too). The routes themselves
|
|
5110
|
-
accept only a uuid — the CLI resolves the key for you, and names the keys that do
|
|
5111
|
-
exist when it cannot. A 403 on a write can be an RBAC grant gap rather than a
|
|
5182
|
+
automation: `octwin automation [campaigns] [--limit n] [--offset n] [--json]
|
|
5183
|
+
No args = every job the pack's automation declaration produced, with its status,
|
|
5184
|
+
interval and LAST RESULT (matched / acted / errors), under a health line whose
|
|
5185
|
+
counts come from SQL rather than from filtering the page — the job list is capped
|
|
5186
|
+
server-side, so a client-side count would depend on the cap. Needs automation:read.
|
|
5187
|
+
|
|
5188
|
+
Jobs are DERIVED from declarations. There is no \`create\`: no automation block in
|
|
5189
|
+
the pack means no jobs, and \`octwin deploy\` is what installs them.
|
|
5190
|
+
|
|
5191
|
+
WRITES (automation:write):
|
|
5192
|
+
octwin automation run <jobId> # run once, now — prints matched/acted/errors
|
|
5193
|
+
octwin automation pause|resume <jobId>
|
|
5194
|
+
octwin automation send <campaignId> # enqueue a campaign; enqueued != delivered
|
|
5195
|
+
|
|
5196
|
+
<jobId> is the \`key\` the list shows (its uuid works too). The routes themselves
|
|
5197
|
+
accept only a uuid — the CLI resolves the key for you, and names the keys that do
|
|
5198
|
+
exist when it cannot. A 403 on a write can be an RBAC grant gap rather than a
|
|
5112
5199
|
missing scope: the action is re-checked against the job.`,
|
|
5113
|
-
integrations: `octwin integrations [--json]
|
|
5114
|
-
What the pack DECLARES beside what is actually CONFIGURED, in one view — because a
|
|
5115
|
-
connection that is declared and never configured is the commonest reason an
|
|
5116
|
-
integration silently never fires, and neither list alone can show it. Flags the
|
|
5117
|
-
gap explicitly. Needs integrations:read.
|
|
5118
|
-
|
|
5119
|
-
DIAGNOSE ONE CONNECTION:
|
|
5120
|
-
octwin integrations preflight <key> # every check, with a fix hint. Makes NO
|
|
5121
|
-
# outbound call — needs only integrations:read
|
|
5122
|
-
octwin integrations test <key> # a LIVE call to its health: operation
|
|
5123
|
-
# (integrations:write). Exits 1 when it fails.
|
|
5124
|
-
|
|
5125
|
-
THE DELIVERY LOG:
|
|
5126
|
-
octwin integrations deliveries [--status s] [--operation id] [--limit n]
|
|
5127
|
-
octwin integrations deliveries <id> # + the redacted request/response snapshots
|
|
5128
|
-
octwin integrations retry|cancel|send-now <id> # integrations:write
|
|
5129
|
-
octwin integrations events # INBOUND events (what arrived at your webhook)
|
|
5130
|
-
|
|
5131
|
-
retry/cancel answer 409 when the delivery is in the wrong state; the message
|
|
5200
|
+
integrations: `octwin integrations [--json]
|
|
5201
|
+
What the pack DECLARES beside what is actually CONFIGURED, in one view — because a
|
|
5202
|
+
connection that is declared and never configured is the commonest reason an
|
|
5203
|
+
integration silently never fires, and neither list alone can show it. Flags the
|
|
5204
|
+
gap explicitly. Needs integrations:read.
|
|
5205
|
+
|
|
5206
|
+
DIAGNOSE ONE CONNECTION:
|
|
5207
|
+
octwin integrations preflight <key> # every check, with a fix hint. Makes NO
|
|
5208
|
+
# outbound call — needs only integrations:read
|
|
5209
|
+
octwin integrations test <key> # a LIVE call to its health: operation
|
|
5210
|
+
# (integrations:write). Exits 1 when it fails.
|
|
5211
|
+
|
|
5212
|
+
THE DELIVERY LOG:
|
|
5213
|
+
octwin integrations deliveries [--status s] [--operation id] [--limit n]
|
|
5214
|
+
octwin integrations deliveries <id> # + the redacted request/response snapshots
|
|
5215
|
+
octwin integrations retry|cancel|send-now <id> # integrations:write
|
|
5216
|
+
octwin integrations events # INBOUND events (what arrived at your webhook)
|
|
5217
|
+
|
|
5218
|
+
retry/cancel answer 409 when the delivery is in the wrong state; the message
|
|
5132
5219
|
carries the rule.`,
|
|
5133
|
-
journeys: `octwin journeys [journeyId] [--funnel|--overview|--goals|--trends|--cost|--definition]
|
|
5134
|
-
[--stage <stageId>] [--limit n] [--json]
|
|
5135
|
-
No args = the journeys the pack declares. With an id, one of six views —
|
|
5136
|
-
--funnel (default) stage-by-stage reach and drop-off · --overview entered vs
|
|
5137
|
-
converted plus the biggest drop-off · --goals completions, contacts, value and
|
|
5138
|
-
p50 time · --trends per-bucket activity · --cost tokens and dollars per goal ·
|
|
5139
|
-
--definition what was DECLARED, unmeasured (the one view that works with no
|
|
5140
|
-
traffic). Needs journeys:read.
|
|
5141
|
-
|
|
5142
|
-
--stage <stageId> lists the runs sitting at a stage right now (a live snapshot,
|
|
5143
|
-
not the funnel's cumulative reached counts).
|
|
5144
|
-
|
|
5145
|
-
Same flag grammar as \`octwin analytics\` on purpose: a journey funnel and an
|
|
5146
|
-
entity funnel are the same question about different subjects. Journeys carry RBAC
|
|
5147
|
-
on top of the scope, so an empty answer can be a missing \`view\` grant rather
|
|
5220
|
+
journeys: `octwin journeys [journeyId] [--funnel|--overview|--goals|--trends|--cost|--definition]
|
|
5221
|
+
[--stage <stageId>] [--limit n] [--json]
|
|
5222
|
+
No args = the journeys the pack declares. With an id, one of six views —
|
|
5223
|
+
--funnel (default) stage-by-stage reach and drop-off · --overview entered vs
|
|
5224
|
+
converted plus the biggest drop-off · --goals completions, contacts, value and
|
|
5225
|
+
p50 time · --trends per-bucket activity · --cost tokens and dollars per goal ·
|
|
5226
|
+
--definition what was DECLARED, unmeasured (the one view that works with no
|
|
5227
|
+
traffic). Needs journeys:read.
|
|
5228
|
+
|
|
5229
|
+
--stage <stageId> lists the runs sitting at a stage right now (a live snapshot,
|
|
5230
|
+
not the funnel's cumulative reached counts).
|
|
5231
|
+
|
|
5232
|
+
Same flag grammar as \`octwin analytics\` on purpose: a journey funnel and an
|
|
5233
|
+
entity funnel are the same question about different subjects. Journeys carry RBAC
|
|
5234
|
+
on top of the scope, so an empty answer can be a missing \`view\` grant rather
|
|
5148
5235
|
than missing data — the output says which causes are possible.`,
|
|
5149
|
-
performance: `octwin performance [--detail] [--json]
|
|
5150
|
-
The project's business indicators — value produced, conversion, duration — each
|
|
5151
|
-
with its delta against the previous window and a \`why\` naming the declaration it
|
|
5152
|
-
came from. --detail adds the per-indicator breakdown.
|
|
5153
|
-
|
|
5154
|
-
Needs records:read, NOT a performance scope (there is none), so a read-only token
|
|
5155
|
-
already reaches it. Indicators are DERIVED: a pack that declares no journey goal
|
|
5236
|
+
performance: `octwin performance [--detail] [--json]
|
|
5237
|
+
The project's business indicators — value produced, conversion, duration — each
|
|
5238
|
+
with its delta against the previous window and a \`why\` naming the declaration it
|
|
5239
|
+
came from. --detail adds the per-indicator breakdown.
|
|
5240
|
+
|
|
5241
|
+
Needs records:read, NOT a performance scope (there is none), so a read-only token
|
|
5242
|
+
already reaches it. Indicators are DERIVED: a pack that declares no journey goal
|
|
5156
5243
|
value and no pipelined entity produces none, which is a different thing from zero.`,
|
|
5157
|
-
usage: `octwin usage [--json]
|
|
5158
|
-
Model calls, tokens and cost for the resolved scope — project when one is pinned
|
|
5159
|
-
or passed with --project, otherwise the whole workspace. Broken down by model,
|
|
5160
|
-
kind, agent and channel.
|
|
5161
|
-
|
|
5162
|
-
Needs no particular scope: any valid token reaches it.
|
|
5163
|
-
|
|
5164
|
-
This is MODEL spend only. WhatsApp/Meta message billing is operator-only and
|
|
5244
|
+
usage: `octwin usage [--json]
|
|
5245
|
+
Model calls, tokens and cost for the resolved scope — project when one is pinned
|
|
5246
|
+
or passed with --project, otherwise the whole workspace. Broken down by model,
|
|
5247
|
+
kind, agent and channel.
|
|
5248
|
+
|
|
5249
|
+
Needs no particular scope: any valid token reaches it.
|
|
5250
|
+
|
|
5251
|
+
This is MODEL spend only. WhatsApp/Meta message billing is operator-only and
|
|
5165
5252
|
deliberately outside the token scope registry — no API token can read it.`,
|
|
5166
|
-
'platform-kb': `octwin platform-kb [pull] [--if-stale] [--check] [--dir .] [--url <url>] [--token <t>]
|
|
5167
|
-
Pull the platform capability reference (markdown + JSON catalogs) into
|
|
5168
|
-
.octwin/platform-kb/ for the octwin-pack authoring skill, plus three maps:
|
|
5169
|
-
INDEX.md (the corpus) · SYMBOLS.md (every name -> its file; grep this) ·
|
|
5170
|
-
OUTLINE.md (every heading with its line number).
|
|
5171
|
-
|
|
5172
|
-
NO TOKEN NEEDED — the reference is platform stdlib and is served anonymously,
|
|
5173
|
-
and this command never sends one. --token is accepted and ignored, so an older
|
|
5174
|
-
script that passes it keeps working.
|
|
5175
|
-
|
|
5176
|
-
--if-stale poll the platform's content_hash first and skip the download when
|
|
5177
|
-
nothing changed. Cheap enough to run at the start of every session.
|
|
5178
|
-
--check report only, write nothing. Exit 0 = current, 2 = stale or never
|
|
5179
|
-
pulled, 1 = could not tell (offline / no reference served). For
|
|
5253
|
+
'platform-kb': `octwin platform-kb [pull] [--if-stale] [--check] [--dir .] [--url <url>] [--token <t>]
|
|
5254
|
+
Pull the platform capability reference (markdown + JSON catalogs) into
|
|
5255
|
+
.octwin/platform-kb/ for the octwin-pack authoring skill, plus three maps:
|
|
5256
|
+
INDEX.md (the corpus) · SYMBOLS.md (every name -> its file; grep this) ·
|
|
5257
|
+
OUTLINE.md (every heading with its line number).
|
|
5258
|
+
|
|
5259
|
+
NO TOKEN NEEDED — the reference is platform stdlib and is served anonymously,
|
|
5260
|
+
and this command never sends one. --token is accepted and ignored, so an older
|
|
5261
|
+
script that passes it keeps working.
|
|
5262
|
+
|
|
5263
|
+
--if-stale poll the platform's content_hash first and skip the download when
|
|
5264
|
+
nothing changed. Cheap enough to run at the start of every session.
|
|
5265
|
+
--check report only, write nothing. Exit 0 = current, 2 = stale or never
|
|
5266
|
+
pulled, 1 = could not tell (offline / no reference served). For
|
|
5180
5267
|
scripts and agent loops that want to branch without parsing prose.`,
|
|
5181
|
-
test: `octwin test [--dir .]
|
|
5268
|
+
test: `octwin test [--dir .]
|
|
5182
5269
|
Alias for \`octwin validate --remote\` — the full platform check.`,
|
|
5183
|
-
memos: `octwin memos [--all] [--json]
|
|
5184
|
-
Read what the platform has told you: a REPLY to a report you sent with
|
|
5185
|
-
\`octwin feedback\`, or a NOTICE published to every author (a new capability,
|
|
5186
|
-
a deprecation, a breaking change). Bodies are printed in full.
|
|
5187
|
-
Reading marks them read, so the reminder stops. --all re-reads history and
|
|
5188
|
-
acks nothing. --json to branch on \`severity\`
|
|
5270
|
+
memos: `octwin memos [--all] [--json]
|
|
5271
|
+
Read what the platform has told you: a REPLY to a report you sent with
|
|
5272
|
+
\`octwin feedback\`, or a NOTICE published to every author (a new capability,
|
|
5273
|
+
a deprecation, a breaking change). Bodies are printed in full.
|
|
5274
|
+
Reading marks them read, so the reminder stops. --all re-reads history and
|
|
5275
|
+
acks nothing. --json to branch on \`severity\`
|
|
5189
5276
|
(info | action_required | breaking).`,
|
|
5190
|
-
feedback: `octwin feedback [--dir .]
|
|
5191
|
-
Submit this pack's FEEDBACK.md to the platform team.
|
|
5192
|
-
The octwin-pack skill writes that file in its last step — findings grouped by
|
|
5193
|
-
owner (A · CLI, B · Platform, C · Skill/KB). This delivers it instead of asking
|
|
5194
|
-
you to paste it into a chat.
|
|
5195
|
-
Attaches the pack id + version from manifest.yaml, this CLI's version, and the
|
|
5196
|
-
content_hash of the capability reference in .octwin/platform-kb/ — triage needs
|
|
5197
|
-
the last two to tell "the platform is wrong" from "that was already fixed" or
|
|
5277
|
+
feedback: `octwin feedback [--dir .]
|
|
5278
|
+
Submit this pack's FEEDBACK.md to the platform team.
|
|
5279
|
+
The octwin-pack skill writes that file in its last step — findings grouped by
|
|
5280
|
+
owner (A · CLI, B · Platform, C · Skill/KB). This delivers it instead of asking
|
|
5281
|
+
you to paste it into a chat.
|
|
5282
|
+
Attaches the pack id + version from manifest.yaml, this CLI's version, and the
|
|
5283
|
+
content_hash of the capability reference in .octwin/platform-kb/ — triage needs
|
|
5284
|
+
the last two to tell "the platform is wrong" from "that was already fixed" or
|
|
5198
5285
|
"you were reading a stale reference". Needs the \`pack:deploy\` scope.`,
|
|
5199
5286
|
};
|
|
5200
5287
|
async function main() {
|