@smartreviq/cli 0.3.1 → 0.3.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/LICENSE.md +16 -0
- package/README.md +1 -1
- package/package.json +3 -8
- package/src/cli.mjs +59 -18
- package/src/client.mjs +10 -3
package/LICENSE.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SmartRevIQ. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software is a component of the SmartRevIQ service. It is published so
|
|
6
|
+
that SmartRevIQ customers can manage the configuration of their own
|
|
7
|
+
SmartRevIQ environments from their own repositories and pipelines.
|
|
8
|
+
|
|
9
|
+
Use is permitted only by parties holding a current subscription to the
|
|
10
|
+
SmartRevIQ service, and is governed by the terms of the agreement under
|
|
11
|
+
which that subscription is held.
|
|
12
|
+
|
|
13
|
+
No other rights are granted. This software may not be redistributed,
|
|
14
|
+
sublicensed, sold, or incorporated into another product or service, and may
|
|
15
|
+
not be reverse engineered except to the extent that such a restriction is
|
|
16
|
+
unenforceable under applicable law.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# sriq
|
|
2
2
|
|
|
3
|
-
Edit, test and ship SmartRevIQ process-engine scripts from
|
|
3
|
+
Edit, test and ship SmartRevIQ process-engine scripts from your editor and CI.
|
|
4
4
|
|
|
5
5
|
No IDE plugin. The CLI writes ordinary project files — `jsconfig.json`, type
|
|
6
6
|
declarations, launch configurations — and both editors read them through the
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smartreviq/cli",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "Edit, test and ship SmartRevIQ process-engine scripts from
|
|
3
|
+
"version": "0.3.3",
|
|
4
|
+
"description": "Edit, test and ship SmartRevIQ process-engine scripts from your editor and CI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"sriq": "bin/sriq.mjs"
|
|
@@ -21,12 +21,7 @@
|
|
|
21
21
|
"acorn": "^8.19.0",
|
|
22
22
|
"typescript": "^5.9.3"
|
|
23
23
|
},
|
|
24
|
-
"license": "
|
|
25
|
-
"repository": {
|
|
26
|
-
"type": "git",
|
|
27
|
-
"url": "git+https://github.com/SmartRevIQ/smartreviq-backend.git",
|
|
28
|
-
"directory": "tools/sriq"
|
|
29
|
-
},
|
|
24
|
+
"license": "SEE LICENSE IN LICENSE.md",
|
|
30
25
|
"publishConfig": {
|
|
31
26
|
"access": "public"
|
|
32
27
|
},
|
package/src/cli.mjs
CHANGED
|
@@ -669,6 +669,22 @@ function localScripts(root) {
|
|
|
669
669
|
return out;
|
|
670
670
|
}
|
|
671
671
|
|
|
672
|
+
/**
|
|
673
|
+
* Every script key the environment holds, as `folder/name.script`.
|
|
674
|
+
*
|
|
675
|
+
* One request. Deliberately NOT wrapped in a try/catch: if this fails, the
|
|
676
|
+
* caller cannot distinguish a script that is absent from one it simply could
|
|
677
|
+
* not read, and every answer it gives afterwards would be invented.
|
|
678
|
+
*/
|
|
679
|
+
async function listRemoteKeys(api) {
|
|
680
|
+
const listing = await api.listScripts();
|
|
681
|
+
const keys = new Set();
|
|
682
|
+
for (const [folder, names] of Object.entries(listing ?? {})) {
|
|
683
|
+
for (const n of names) if (n.endsWith('.script')) keys.add(`${folder}/${n}`);
|
|
684
|
+
}
|
|
685
|
+
return keys;
|
|
686
|
+
}
|
|
687
|
+
|
|
672
688
|
async function cmdPush(argv) {
|
|
673
689
|
const { root, config, target, flags, positional } = projectTarget(argv);
|
|
674
690
|
const api = clientFor(target);
|
|
@@ -680,6 +696,7 @@ async function cmdPush(argv) {
|
|
|
680
696
|
log(`${yellow('→')} target: ${bold(target.env)} ${dim(target.api)}`);
|
|
681
697
|
}
|
|
682
698
|
const platform = platformOwned(root);
|
|
699
|
+
const remoteKeys = await listRemoteKeys(api);
|
|
683
700
|
|
|
684
701
|
let targets = localScripts(root);
|
|
685
702
|
if (positional.length) {
|
|
@@ -714,11 +731,17 @@ async function cmdPush(argv) {
|
|
|
714
731
|
}
|
|
715
732
|
|
|
716
733
|
const body = unwrap(text);
|
|
717
|
-
|
|
718
|
-
|
|
734
|
+
const key = `${t.folder}/${s3Name}`;
|
|
735
|
+
if (!remoteKeys.has(key)) {
|
|
736
|
+
changed.push({ ...t, s3Name, body, isNew: true });
|
|
737
|
+
continue;
|
|
738
|
+
}
|
|
739
|
+
// Existence came from the listing; this only answers "has it changed".
|
|
740
|
+
// Reading a failure here as "new" is what let an expired token report a
|
|
741
|
+
// whole project as added — see listRemoteKeys.
|
|
742
|
+
const remote = await api.getScript(s3Name, t.folder);
|
|
719
743
|
if (remote === body) continue;
|
|
720
|
-
|
|
721
|
-
changed.push({ ...t, s3Name, body, isNew: remote === null });
|
|
744
|
+
changed.push({ ...t, s3Name, body, isNew: false });
|
|
722
745
|
}
|
|
723
746
|
|
|
724
747
|
if (blocked.length) {
|
|
@@ -756,14 +779,26 @@ async function cmdStatus(argv) {
|
|
|
756
779
|
const api = clientFor(target);
|
|
757
780
|
|
|
758
781
|
const locals = localScripts(root);
|
|
782
|
+
|
|
783
|
+
// THE LISTING DECIDES WHAT EXISTS. It used to be inferred: fetch each script
|
|
784
|
+
// and treat any failure as "not there". That reads a 401 as a new script, so
|
|
785
|
+
// an expired token — they last an hour — turned a clean status into every
|
|
786
|
+
// file reported as added. Observed on a 422-script project, which also
|
|
787
|
+
// showed how convincing the wrong answer looks.
|
|
788
|
+
//
|
|
789
|
+
// The error code cannot rescue that inference either: a script that really
|
|
790
|
+
// is absent comes back 500 SYSTEM_ERROR, the same as a server fault. So the
|
|
791
|
+
// guess is replaced by the one authoritative answer, which this command was
|
|
792
|
+
// already fetching for orphan detection, and a failure to get it is fatal
|
|
793
|
+
// rather than best-effort — without it, A and M cannot be told apart.
|
|
794
|
+
const remoteKeys = await listRemoteKeys(api);
|
|
759
795
|
const rows = [];
|
|
760
796
|
for (const t of locals) {
|
|
761
|
-
const
|
|
797
|
+
const key = `${t.folder}/${toRemoteName(t.localName)}`;
|
|
798
|
+
if (!remoteKeys.has(key)) { rows.push(['A', `${t.folder}/${t.localName}`]); continue; }
|
|
762
799
|
const body = unwrap(readFileSync(t.absPath, 'utf8'));
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
if (remote === null) rows.push(['A', `${t.folder}/${t.localName}`]);
|
|
766
|
-
else if (remote !== body) rows.push(['M', `${t.folder}/${t.localName}`]);
|
|
800
|
+
const remote = await api.getScript(toRemoteName(t.localName), t.folder);
|
|
801
|
+
if (remote !== body) rows.push(['M', `${t.folder}/${t.localName}`]);
|
|
767
802
|
}
|
|
768
803
|
|
|
769
804
|
// Scripts live on the environment with no local file. `push` only ever
|
|
@@ -776,13 +811,8 @@ async function cmdStatus(argv) {
|
|
|
776
811
|
// and the real answer is simply `sriq pull`.
|
|
777
812
|
let orphans = [];
|
|
778
813
|
if (locals.length) {
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
const here = new Set(locals.map((t) => `${t.folder}/${toRemoteName(t.localName)}`));
|
|
782
|
-
orphans = Object.entries(listing)
|
|
783
|
-
.flatMap(([folder, names]) => names.map((n) => `${folder}/${n}`))
|
|
784
|
-
.filter((k) => !here.has(k));
|
|
785
|
-
} catch { /* best effort — the per-script diff above is the contract */ }
|
|
814
|
+
const here = new Set(locals.map((t) => `${t.folder}/${toRemoteName(t.localName)}`));
|
|
815
|
+
orphans = [...remoteKeys].filter((k) => !here.has(k));
|
|
786
816
|
}
|
|
787
817
|
|
|
788
818
|
log(`${bold(target.env)} ${dim(target.api + (target.apiPrefix ?? DEFAULT_API_PREFIX))}`);
|
|
@@ -824,7 +854,7 @@ async function cmdRun(argv) {
|
|
|
824
854
|
|
|
825
855
|
if (!safeMode) log(yellow('! running with writes ENABLED (--unsafe)'));
|
|
826
856
|
|
|
827
|
-
if (flags.local) return runLocally({ abs, api,
|
|
857
|
+
if (flags.local) return runLocally({ abs, api, root, target, flags, safeMode });
|
|
828
858
|
|
|
829
859
|
let result;
|
|
830
860
|
if (flags.doc) {
|
|
@@ -844,7 +874,18 @@ async function cmdRun(argv) {
|
|
|
844
874
|
* every api call forwarded to the environment. See runner.mjs for the fidelity
|
|
845
875
|
* caveat this prints.
|
|
846
876
|
*/
|
|
847
|
-
|
|
877
|
+
/**
|
|
878
|
+
* `--local` was dead on arrival. Three names this function uses were never
|
|
879
|
+
* passed to it — `config`, which it does not actually need, plus `root` and
|
|
880
|
+
* `target`, which it does — so every invocation threw `config is not defined`
|
|
881
|
+
* before reaching the runner, and the next two were waiting behind it.
|
|
882
|
+
*
|
|
883
|
+
* The runner's own tests pass and always did: they exercise runner.mjs
|
|
884
|
+
* directly, never the handful of lines of CLI wiring between the flag and it.
|
|
885
|
+
* A test that spawns the command is the only thing that would have caught
|
|
886
|
+
* this, which is why one now exists.
|
|
887
|
+
*/
|
|
888
|
+
async function runLocally({ abs, api, root, target, flags, safeMode }) {
|
|
848
889
|
const { createRemoteApi, installGlobals, runScriptFile } = await import('./runner.mjs');
|
|
849
890
|
|
|
850
891
|
let doc = null;
|
package/src/client.mjs
CHANGED
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
* reads as rejected credentials rather than as a misrouted request.
|
|
26
26
|
*
|
|
27
27
|
* Both Lambdas rewrite `/api/v1/` to `/api/` before their own routers see the
|
|
28
|
-
* path
|
|
29
|
-
*
|
|
28
|
+
* path, so the prefixed form is correct for every endpoint listed above, on
|
|
29
|
+
* every environment.
|
|
30
30
|
*
|
|
31
31
|
* Overridable per project through `.sriq.json` "apiPrefix", so an environment
|
|
32
32
|
* that routes differently can be worked around without waiting for a release.
|
|
@@ -79,8 +79,15 @@ export class Client {
|
|
|
79
79
|
// matters most — an SSO-only account being refused a password login
|
|
80
80
|
// reads as an expired session, which it is not.
|
|
81
81
|
const said = parsed?.message || parsed?.error;
|
|
82
|
+
// The status goes in the text even when the server said something
|
|
83
|
+
// useful. Without it "Invalid token" is just a sentence: it does not
|
|
84
|
+
// say an AUTH check failed, so it reads as a problem with the script
|
|
85
|
+
// or the request. A reader who sees 401 knows to re-authenticate
|
|
86
|
+
// without being told to — which matters, because telling them to would
|
|
87
|
+
// be wrong for the SSO-only account this branch exists to serve.
|
|
82
88
|
throw new ApiError(
|
|
83
|
-
said
|
|
89
|
+
said ? `${said} (401 — ${method} ${fullPath})`
|
|
90
|
+
: 'Unauthorized. Your session may have expired — run `sriq login`.',
|
|
84
91
|
401, parsed
|
|
85
92
|
);
|
|
86
93
|
}
|