@nwire/please 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +52 -0
- package/dist/please.d.ts +39 -0
- package/dist/please.d.ts.map +1 -0
- package/dist/please.js +77 -0
- package/dist/please.js.map +1 -0
- package/package.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alex Gefter / 200apps Ltd.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# @nwire/please
|
|
2
|
+
|
|
3
|
+
> Operator CLI — dispatch any registered action or query from the command line.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
Looks at every app's registered actions and queries and exposes them as CLI commands. `please submissions.flag-for-review --submissionId xyz` walks the apps registry, finds the owning app, seeds an envelope, dispatches, prints the result. Same handlers as HTTP/queue — operator parity guaranteed.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @nwire/please
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
#!/usr/bin/env node
|
|
19
|
+
import { runPlease } from "@nwire/please";
|
|
20
|
+
import { apps } from "../app/apps";
|
|
21
|
+
|
|
22
|
+
runPlease({ apps, argv: process.argv.slice(2) }).then((code) => process.exit(code));
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
please submissions.flag-for-review --submissionId xyz --confidence 0.4
|
|
27
|
+
please lessons.start-attempt --lessonId hebrew-1 --studentId avi
|
|
28
|
+
please submissions.by-student --studentId avi --status under-review
|
|
29
|
+
please --help
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## API surface
|
|
33
|
+
|
|
34
|
+
- `runPlease({ apps, appInstances?, argv, stdout?, stderr? })` — returns exit code.
|
|
35
|
+
|
|
36
|
+
## When to use
|
|
37
|
+
|
|
38
|
+
Operations work — re-run a stuck workflow, query a projection, kick a one-off action — without writing a script or shelling into a worker. Fits L3 and up.
|
|
39
|
+
|
|
40
|
+
## Used only within nwire-app
|
|
41
|
+
|
|
42
|
+
This package is part of the Nwire stack — it only makes sense inside a Nwire application built with `@nwire/app` + `@nwire/forge`. If you're looking for a standalone primitive, see:
|
|
43
|
+
|
|
44
|
+
- [`@nwire/handler`](../nwire-handler/README.md) — the operation primitive (transport-agnostic)
|
|
45
|
+
- [`@nwire/hooks`](../nwire-hooks/README.md) — universal dispatch (chain + listeners)
|
|
46
|
+
- [`@nwire/http`](../nwire-http/README.md) — typed HTTP without forge
|
|
47
|
+
- [`@nwire/endpoint`](../nwire-endpoint/README.md) — graceful shutdown for any host
|
|
48
|
+
|
|
49
|
+
## See also
|
|
50
|
+
|
|
51
|
+
- [Architecture sketch §05 — Tooling](../../architecture-sketch.html#packages)
|
|
52
|
+
- Sibling packages: [@nwire/cli](../nwire-cli), [@nwire/mcp](../nwire-mcp)
|
package/dist/please.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@nwire/please` — operator CLI for Nwire apps.
|
|
3
|
+
*
|
|
4
|
+
* #!/usr/bin/env node
|
|
5
|
+
* import { runPlease } from '@nwire/please'
|
|
6
|
+
* import { apps } from '../app/apps'
|
|
7
|
+
*
|
|
8
|
+
* runPlease({ apps, argv: process.argv.slice(2) }).then(code => process.exit(code))
|
|
9
|
+
*
|
|
10
|
+
* The CLI dispatches against any registered action or query in any app.
|
|
11
|
+
* please submissions.flag-for-review --submissionId xyz --confidence 0.4
|
|
12
|
+
* please lessons.start-attempt --lessonId hebrew-1 --studentId avi
|
|
13
|
+
* please submissions.by-student --studentId avi --status under-review
|
|
14
|
+
* please --help
|
|
15
|
+
*
|
|
16
|
+
* Scaffolding (`make:module`, `make:action`, `make:projection`) lands as a
|
|
17
|
+
* follow-up phase — the CLI runner is the primitive, scaffolders compose on top.
|
|
18
|
+
*/
|
|
19
|
+
import * as forge from "@nwire/forge";
|
|
20
|
+
export interface RunPleaseOptions {
|
|
21
|
+
/** Apps to expose. The CLI dispatches against any action/query in any of these. */
|
|
22
|
+
readonly apps: readonly forge.AppDefinition[];
|
|
23
|
+
/** Pre-instantiated `App`s (for tests where stores are injected). */
|
|
24
|
+
readonly appInstances?: readonly forge.App[];
|
|
25
|
+
/** Argv slice, typically `process.argv.slice(2)`. */
|
|
26
|
+
readonly argv: readonly string[];
|
|
27
|
+
/** stdout override (tests). Default: console.log. */
|
|
28
|
+
readonly stdout?: (line: string) => void;
|
|
29
|
+
/** stderr override (tests). Default: console.error. */
|
|
30
|
+
readonly stderr?: (line: string) => void;
|
|
31
|
+
/** Hook for store/logger overrides at instantiation time. */
|
|
32
|
+
readonly createOverrides?: (appDef: forge.AppDefinition) => Omit<forge.CreateAppOptions, "modules">;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Boot every registered app, run the dispatched action/query against the
|
|
36
|
+
* matching app, return the exit code (0 on success, 1 on error).
|
|
37
|
+
*/
|
|
38
|
+
export declare function runPlease(options: RunPleaseOptions): Promise<number>;
|
|
39
|
+
//# sourceMappingURL=please.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"please.d.ts","sourceRoot":"","sources":["../src/please.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAEtC,MAAM,WAAW,gBAAgB;IAC/B,mFAAmF;IACnF,QAAQ,CAAC,IAAI,EAAE,SAAS,KAAK,CAAC,aAAa,EAAE,CAAC;IAC9C,qEAAqE;IACrE,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,KAAK,CAAC,GAAG,EAAE,CAAC;IAC7C,qDAAqD;IACrD,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,qDAAqD;IACrD,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,uDAAuD;IACvD,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,6DAA6D;IAC7D,QAAQ,CAAC,eAAe,CAAC,EAAE,CACzB,MAAM,EAAE,KAAK,CAAC,aAAa,KACxB,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;CAC9C;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6B1E"}
|
package/dist/please.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@nwire/please` — operator CLI for Nwire apps.
|
|
3
|
+
*
|
|
4
|
+
* #!/usr/bin/env node
|
|
5
|
+
* import { runPlease } from '@nwire/please'
|
|
6
|
+
* import { apps } from '../app/apps'
|
|
7
|
+
*
|
|
8
|
+
* runPlease({ apps, argv: process.argv.slice(2) }).then(code => process.exit(code))
|
|
9
|
+
*
|
|
10
|
+
* The CLI dispatches against any registered action or query in any app.
|
|
11
|
+
* please submissions.flag-for-review --submissionId xyz --confidence 0.4
|
|
12
|
+
* please lessons.start-attempt --lessonId hebrew-1 --studentId avi
|
|
13
|
+
* please submissions.by-student --studentId avi --status under-review
|
|
14
|
+
* please --help
|
|
15
|
+
*
|
|
16
|
+
* Scaffolding (`make:module`, `make:action`, `make:projection`) lands as a
|
|
17
|
+
* follow-up phase — the CLI runner is the primitive, scaffolders compose on top.
|
|
18
|
+
*/
|
|
19
|
+
import * as forge from "@nwire/forge";
|
|
20
|
+
/**
|
|
21
|
+
* Boot every registered app, run the dispatched action/query against the
|
|
22
|
+
* matching app, return the exit code (0 on success, 1 on error).
|
|
23
|
+
*/
|
|
24
|
+
export async function runPlease(options) {
|
|
25
|
+
const instances = options.appInstances?.slice() ??
|
|
26
|
+
options.apps.map((def) => def.create(options.createOverrides?.(def) ?? {}));
|
|
27
|
+
await Promise.all(instances.map((a) => a.start()));
|
|
28
|
+
// Find which app owns the named action/query and run against THAT app.
|
|
29
|
+
// For now, if argv[0] is a name found in any app, dispatch through that.
|
|
30
|
+
// Multi-app `please <app>:<action>` syntax lands when needed.
|
|
31
|
+
const argv = options.argv;
|
|
32
|
+
const stdout = options.stdout;
|
|
33
|
+
const stderr = options.stderr;
|
|
34
|
+
if (argv.length === 0 || argv[0] === "--help" || argv[0] === "-h") {
|
|
35
|
+
printAllHelp(instances, options.stdout ?? ((l) => console.log(l)));
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
const targetName = argv[0];
|
|
39
|
+
const owner = instances.find((a) => actionOrQueryNames(a).includes(targetName));
|
|
40
|
+
if (!owner) {
|
|
41
|
+
(options.stderr ?? ((l) => console.error(l)))(`unknown action or query: "${targetName}". Run with --help.`);
|
|
42
|
+
return 1;
|
|
43
|
+
}
|
|
44
|
+
return forge.runCli(owner, argv, { stdout, stderr });
|
|
45
|
+
}
|
|
46
|
+
function actionOrQueryNames(app) {
|
|
47
|
+
const actions = [];
|
|
48
|
+
for (const module of app.modules) {
|
|
49
|
+
for (const action of module.manifest.actions ?? [])
|
|
50
|
+
actions.push(action.name);
|
|
51
|
+
for (const query of module.manifest.queries ?? [])
|
|
52
|
+
actions.push(query.name);
|
|
53
|
+
}
|
|
54
|
+
return actions;
|
|
55
|
+
}
|
|
56
|
+
function printAllHelp(instances, out) {
|
|
57
|
+
out("please — Nwire operator CLI\n");
|
|
58
|
+
out("Usage: please <action-or-query-name> [--field value ...] [--tenant <id>]\n");
|
|
59
|
+
for (const app of instances) {
|
|
60
|
+
out(`# App: ${describeApp(app)}`);
|
|
61
|
+
for (const module of app.modules) {
|
|
62
|
+
for (const action of module.manifest.actions ?? []) {
|
|
63
|
+
out(` ${action.name}${action.description ? " — " + action.description.slice(0, 70) : ""}`);
|
|
64
|
+
}
|
|
65
|
+
for (const query of module.manifest.queries ?? []) {
|
|
66
|
+
out(` ${query.name}${query.description ? " — " + query.description.slice(0, 70) : ""}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
out("");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function describeApp(app) {
|
|
73
|
+
// The runtime doesn't expose the app's name yet; defer naming until
|
|
74
|
+
// `App` carries its AppDefinition reference. Today: show module count.
|
|
75
|
+
return `${app.modules.length} module${app.modules.length === 1 ? "" : "s"}`;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=please.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"please.js","sourceRoot":"","sources":["../src/please.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nwire/please",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "Nwire — operator CLI. runPlease dispatches actions/queries by name across all registered apps; --tenant for tenant scoping; --help lists everything. Scaffolding (make:module / make:action) lands on top.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ace",
|
|
7
|
+
"artisan",
|
|
8
|
+
"cli",
|
|
9
|
+
"nwire",
|
|
10
|
+
"please"
|
|
11
|
+
],
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./dist/please.js",
|
|
18
|
+
"types": "./dist/please.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": "./dist/please.js",
|
|
22
|
+
"types": "./dist/please.d.ts"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@nwire/forge": "0.7.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^22.19.9",
|
|
33
|
+
"typescript": "^5.9.3"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc && node ../../scripts/fix-dist-extensions.mjs dist",
|
|
37
|
+
"dev": "tsc --watch",
|
|
38
|
+
"typecheck": "tsc --noEmit"
|
|
39
|
+
}
|
|
40
|
+
}
|