@synopackageland/cli 0.41.12 → 0.42.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/CHANGELOG.md +43 -0
- package/README.md +27 -12
- package/dist/ctl/cli.d.ts +5 -0
- package/dist/ctl/cli.js +12 -5
- package/dist/ctl/descriptor.js +2 -1
- package/dist/ctl/input.d.ts +5 -1
- package/dist/ctl/input.js +28 -14
- package/dist/ctl/pattern.d.ts +12 -0
- package/dist/ctl/pattern.js +10 -0
- package/dist/ctl/redaction.js +21 -2
- package/dist/ctl/service.d.ts +17 -5
- package/dist/ctl/service.js +33 -22
- package/dist/e2e/app-open.js +5 -1
- package/dist/error-registry.js +2 -2
- package/dist/host/package-commands.d.ts +15 -0
- package/dist/host/package-commands.js +15 -4
- package/dist/runtime/sdk-source.d.ts +2 -0
- package/dist/runtime/sdk-source.js +2 -0
- package/dist/spk/archive-inventory.d.ts +9 -0
- package/dist/spk/archive-inventory.js +65 -0
- package/dist/spk/check-payload.js +9 -0
- package/dist/spk/rules.d.ts +5 -0
- package/dist/spk/rules.js +1 -0
- package/dist/spk/validate-spk.js +12 -0
- package/dist/standalone/compose.js +4 -4
- package/dist/standalone/daemon-ingress.d.ts +3 -2
- package/dist/standalone/daemon-ingress.js +12 -9
- package/dist/standalone/daemon-restart.d.ts +1 -1
- package/dist/standalone/daemon-restart.js +3 -3
- package/dist/standalone/daemon.d.ts +2 -2
- package/dist/standalone/daemon.js +5 -5
- package/dist/standalone/inspect-bridge.d.ts +3 -1
- package/dist/standalone/inspect-bridge.js +6 -3
- package/dist/standalone/inspect-spk.js +27 -7
- package/dist/standalone/install-settings.js +2 -2
- package/dist/standalone/manifest.js +1 -1
- package/dist/standalone/native-layout.js +18 -1
- package/dist/template-paths.d.ts +0 -4
- package/dist/template-paths.js +0 -11
- package/docs/ctl-external.md +16 -0
- package/package.json +3 -2
- package/skills/SKILL.md +1 -1
- package/skills/reference/ctl.md +24 -0
- package/skills/reference/daemon-mode.md +5 -0
- package/skills/reference/install.md +1 -1
|
@@ -257,10 +257,27 @@ export function checkLayoutMetadata(root, inspection = false, packageId) {
|
|
|
257
257
|
if (/\\\s*$/m.test(unit))
|
|
258
258
|
fail('systemd unit continuations are unsupported');
|
|
259
259
|
let section = '';
|
|
260
|
+
// These settings either describe ordering or operate on the package
|
|
261
|
+
// process. Manager actions/dependencies and filesystem setup are absent.
|
|
262
|
+
const directives = {
|
|
263
|
+
Unit: ['Description', 'Documentation', 'After', 'Before'],
|
|
264
|
+
Service: ['Type', 'User', 'Group', 'ExecStart', 'ExecStartPre', 'ExecStartPost', 'ExecStop', 'ExecStopPost', 'ExecReload',
|
|
265
|
+
'Restart', 'RestartSec', 'TimeoutStartSec', 'TimeoutStopSec', 'KillMode', 'KillSignal', 'WorkingDirectory', 'Environment'],
|
|
266
|
+
Install: ['WantedBy'],
|
|
267
|
+
};
|
|
260
268
|
for (const line of unit.split('\n')) {
|
|
269
|
+
if (!line.trim() || /^\s*[#;]/.test(line))
|
|
270
|
+
continue;
|
|
261
271
|
const heading = line.match(/^\s*\[([^\]]+)\]\s*$/);
|
|
262
|
-
if (heading)
|
|
272
|
+
if (heading) {
|
|
263
273
|
section = heading[1];
|
|
274
|
+
if (!Object.hasOwn(directives, section))
|
|
275
|
+
fail(`unsupported systemd section: ${section}`);
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
const assignment = line.match(/^\s*([A-Za-z][A-Za-z0-9]*)\s*=/);
|
|
279
|
+
if (!assignment || !Object.hasOwn(directives, section) || !directives[section].includes(assignment[1]))
|
|
280
|
+
fail(`unsupported systemd unit directive in ${section || 'missing section'}`);
|
|
264
281
|
if (/^\s*(?:User|Group|Exec\w*)\s*=/.test(line) && section !== 'Service')
|
|
265
282
|
fail('systemd execution directives require the package Service section');
|
|
266
283
|
}
|
package/dist/template-paths.d.ts
CHANGED
|
@@ -3,7 +3,3 @@
|
|
|
3
3
|
* package; SYNOPKGLAND_TEMPLATES_DIR points at a templates checkout instead.
|
|
4
4
|
*/
|
|
5
5
|
export declare function templatesRoot(env?: NodeJS.ProcessEnv, from?: string): string;
|
|
6
|
-
/** The installed templates' SDK pin also supplies CLI-owned runtime defaults.
|
|
7
|
-
* CLI-only patch releases must never turn their own version into an SDK tag.
|
|
8
|
-
*/
|
|
9
|
-
export declare function templateSdkVersion(env?: NodeJS.ProcessEnv): string;
|
package/dist/template-paths.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
|
-
import { sdkRequirement } from "./runtime/sdk-source.js";
|
|
4
3
|
/**
|
|
5
4
|
* The scaffold templates come from the locally installed @synopackageland/templates
|
|
6
5
|
* package; SYNOPKGLAND_TEMPLATES_DIR points at a templates checkout instead.
|
|
@@ -15,13 +14,3 @@ export function templatesRoot(env = process.env, from = import.meta.url) {
|
|
|
15
14
|
throw new Error("[TEMPLATES_MISSING] @synopackageland/templates is not installed; reinstall @synopackageland/cli, or set SYNOPKGLAND_TEMPLATES_DIR to a templates checkout.");
|
|
16
15
|
}
|
|
17
16
|
}
|
|
18
|
-
/** The installed templates' SDK pin also supplies CLI-owned runtime defaults.
|
|
19
|
-
* CLI-only patch releases must never turn their own version into an SDK tag.
|
|
20
|
-
*/
|
|
21
|
-
export function templateSdkVersion(env = process.env) {
|
|
22
|
-
const version = sdkRequirement(join(templatesRoot(env), "native-go/backend"));
|
|
23
|
-
if (!version || !/^\d+\.\d+\.\d+$/.test(version)) {
|
|
24
|
-
throw new Error("[TEMPLATES_MISSING] The installed templates have no valid SDK pin; reinstall @synopackageland/templates.");
|
|
25
|
-
}
|
|
26
|
-
return version;
|
|
27
|
-
}
|
package/docs/ctl-external.md
CHANGED
|
@@ -68,6 +68,22 @@ selected live descriptor against its approved hash. Zero or multiple matching
|
|
|
68
68
|
Apps refuse; revoke the unwanted approval or use distinct protocol IDs. A cache
|
|
69
69
|
is only a recipient selector and never grants tool authority.
|
|
70
70
|
|
|
71
|
+
For ordinary `ctl <alias|package> …` and help requests, an installed App awaiting
|
|
72
|
+
first approval, a new version's approval, or approval of a changed description
|
|
73
|
+
returns `CTL_APP_NEEDS_APPROVAL` (exit 4). For example, the message is
|
|
74
|
+
`SynoReclaim 1.2.0 needs approval` with an App-scoped command:
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
synopkgland ctl list --app SynoReclaim --approve-installed --host controller
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Obtain the user's authorization before running the hint. Cached aliases from the
|
|
81
|
+
previously approved version still identify an upgraded installed App, but cannot
|
|
82
|
+
authorize execution. Before an alias has been discovered, use the package ID for
|
|
83
|
+
first approval. Unknown-name suggestions appear only if no installed package ID
|
|
84
|
+
or known alias matches. `ctl list` includes pending approvals in its diagnostics;
|
|
85
|
+
external calls retain the separate protocol/pin checks described below.
|
|
86
|
+
|
|
71
87
|
Only a named, registered host and its OS-stored session are used. Ambient
|
|
72
88
|
`DSM_*` credentials/URL cannot create or replace this login. HTTPS requires the
|
|
73
89
|
stored SHA-256 certificate pin and refuses rotation before sending HTTP headers,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synopackageland/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.42.0",
|
|
4
4
|
"description": "Syno Package Land Developer Kit CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -28,10 +28,11 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@napi-rs/keyring": "^2.1.1",
|
|
31
|
-
"@synopackageland/templates": "~0.
|
|
31
|
+
"@synopackageland/templates": "~0.37.0",
|
|
32
32
|
"ajv": "^8.17.1",
|
|
33
33
|
"commander": "^13.1.0",
|
|
34
34
|
"json-canonicalize": "^3.0.1",
|
|
35
|
+
"re2js": "2.9.1",
|
|
35
36
|
"tar": "^7.4.3",
|
|
36
37
|
"yaml": "^2.7.0"
|
|
37
38
|
},
|
package/skills/SKILL.md
CHANGED
|
@@ -5,7 +5,7 @@ description: Initialize, extend, check, build, inspect, and deploy Synology appl
|
|
|
5
5
|
|
|
6
6
|
# Independent Synology SPKs
|
|
7
7
|
|
|
8
|
-
The CLI installs templates through `~0.
|
|
8
|
+
The CLI installs templates through `~0.37.0`. A templates patch needs only a
|
|
9
9
|
templates release; npm install/update selects a patch in that minor line. The CLI
|
|
10
10
|
uses the locally installed templates and reads their SDK pin for defaults; it
|
|
11
11
|
never downloads templates at runtime. Preserve the lockfile and use `npm ci` for
|
package/skills/reference/ctl.md
CHANGED
|
@@ -10,8 +10,30 @@ Use this for operating installed Apps, rather than building/deploying projects.
|
|
|
10
10
|
4. Use the discovered alias, CLI path and typed flags with an explicit `--host nas`; inspect `--help` and `--dry-run` before execution. For example, `synopkgland ctl notes list --status pending --host nas --dry-run`. Use the real command/schema from discovery, not this illustrative name.
|
|
11
11
|
5. Reads need no write confirmation. For authorized write/destructive commands, add `--yes`; without it the CLI returns a plan and confirmation error. A --yes flag does not replace the user's authorization or the App's backend checks.
|
|
12
12
|
|
|
13
|
+
Typed flags accept strings, integers, numbers and booleans, including arrays of
|
|
14
|
+
these scalar types. Repeat an array flag for each item, for example
|
|
15
|
+
`--targets /volume1 --targets /volume2`; one occurrence still produces an array.
|
|
16
|
+
Use `--flag=value` when a string item starts with `--`. Commas are literal string
|
|
17
|
+
content, not array separators. Items and the complete array are checked against
|
|
18
|
+
the command schema. Command `--help` lists each supported flag's `valueType` and
|
|
19
|
+
`repeatable` status and renders scalar-array examples as repeated flags.
|
|
20
|
+
Objects, arrays of objects, nested arrays and arrays without a scalar item type
|
|
21
|
+
require `--input <file|->`; use JSON input for an explicit empty array too.
|
|
22
|
+
Plans keep schema-marked private paths and other sensitive values redacted.
|
|
23
|
+
|
|
13
24
|
With multiple hosts, select a default with `synopkgland host default <name>` or specify --host. `--host a,b` and --all-hosts return per-host results, with exit 8 on partial failure. Do not retry a write merely because one host failed; query its state first. --refresh rereads descriptions; unchanged package versions use the host/account/package/version/hash cache. Never assume cached metadata grants resource permission.
|
|
14
25
|
|
|
26
|
+
An installed App awaiting first approval, approval of a new version, or approval
|
|
27
|
+
of a changed description returns `CTL_APP_NEEDS_APPROVAL` (exit 4) when selected
|
|
28
|
+
by package ID or a known cached alias, including help requests. The message names
|
|
29
|
+
the installed package and version, for example `SynoReclaim 1.2.0 needs approval`.
|
|
30
|
+
Obtain the user's authorization, then follow the exact App-scoped hint:
|
|
31
|
+
`synopkgland ctl list --app SynoReclaim --approve-installed --host <profile>`.
|
|
32
|
+
Previous-version aliases identify the installed App only; they never authorize
|
|
33
|
+
execution. An alias not yet discovered requires the package ID for first approval.
|
|
34
|
+
`CTL_APP_UNKNOWN` and “Did you mean …” apply only when no installed package ID or
|
|
35
|
+
known alias matches. `ctl list` reports pending approvals in `data.diagnostics`.
|
|
36
|
+
|
|
15
37
|
Use `host show nas` to inspect approvals/pins, `host revoke nas PackageID` to remove an App approval, `host logout nas` to retain registration, and `host remove nas --yes` to delete sessions, device token, approvals and cache. A failed NAS logout is reported independently from successful local removal.
|
|
16
38
|
|
|
17
39
|
Stdout defaults to JSON without a TTY. Success is {ok:true,data}; failure is {ok:false,error:{code,message,hint,allowed?}}. Multi-host output uses {ok,results:[{host,ok,data|error}]}. Follow the concrete hint and complete allowed list; do not guess another method or bypass ctl with raw HTTP. Exit codes: 2 authentication, 3 parameters/names, 4 permissions/trust, 5 App/contract, 6 network, 7 confirmation, 8 partial failure.
|
|
@@ -163,6 +185,8 @@ For AI consumers: execute commands that describe a complete task. Do not manuall
|
|
|
163
185
|
|
|
164
186
|
App authors must mark passkeys, tokens, private URLs, torrent/base64 and upload content with standard JSON Schema `writeOnly: true`, including nested objects, array items and local references. Mark sensitive response fields in resultSchema too. Do not embed real secrets in schema defaults/enums/examples or command examples.
|
|
165
187
|
|
|
188
|
+
Parameter and result schema `pattern` and `patternProperties` use the linear RE2 engine, with at most 4096 characters per pattern. Backreferences, lookarounds and other unsupported syntax are rejected during description validation. If an unvalidated or cached privacy pattern cannot be compiled, redaction conservatively applies that pattern's annotations to every property.
|
|
189
|
+
|
|
166
190
|
CLI plans, dry-run, missing-yes errors, JSON/multi-host output and known input values repeated by the App use the fixed string `<redacted>`. Schema validation errors never echo instance values or paths. This changes presentation only: authorized requests still send the original values. The CLI does not log or cache business parameters. Sensitive description examples/defaults are masked in list/help and disk caches; a cache altered by redaction requires a fresh authenticated description/hash check before execution. Fill placeholders locally; never paste secrets into AI messages or logs.
|
|
167
191
|
|
|
168
192
|
## Command naming recommendations
|
|
@@ -6,6 +6,11 @@ for every request, and the process exits when the request ends. With
|
|
|
6
6
|
the same binary runs once as the package daemon and serves the pages through
|
|
7
7
|
DSM's nginx. The CGI stays for integrations, transfers and fallback.
|
|
8
8
|
|
|
9
|
+
Set `daemon.ingress.path` to exactly `/synopkgland/<package>/`, preserving the
|
|
10
|
+
manifest package ID's case. The backend mounts routes at
|
|
11
|
+
`SYNOPKGLAND_INGRESS_PATH`; build, inspect and smoke entry checks bind this path
|
|
12
|
+
to the package.
|
|
13
|
+
|
|
9
14
|
Daemon mode is not the default recommendation. It removes work that repeats
|
|
10
15
|
on every request. It does not make a single expensive request cheaper, and it
|
|
11
16
|
costs memory for as long as the package runs. Measure first, then decide.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Native installation settings
|
|
2
2
|
|
|
3
|
-
Use SDK/App 0.
|
|
3
|
+
Use SDK/App 0.41.1, CLI 0.42.0 and templates 0.37.0. Configure installation through the manifest and generated wizard; do not add App ACL writers, root hooks or independent port state.
|
|
4
4
|
|
|
5
5
|
```yaml
|
|
6
6
|
install:
|