@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.
Files changed (45) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +27 -12
  3. package/dist/ctl/cli.d.ts +5 -0
  4. package/dist/ctl/cli.js +12 -5
  5. package/dist/ctl/descriptor.js +2 -1
  6. package/dist/ctl/input.d.ts +5 -1
  7. package/dist/ctl/input.js +28 -14
  8. package/dist/ctl/pattern.d.ts +12 -0
  9. package/dist/ctl/pattern.js +10 -0
  10. package/dist/ctl/redaction.js +21 -2
  11. package/dist/ctl/service.d.ts +17 -5
  12. package/dist/ctl/service.js +33 -22
  13. package/dist/e2e/app-open.js +5 -1
  14. package/dist/error-registry.js +2 -2
  15. package/dist/host/package-commands.d.ts +15 -0
  16. package/dist/host/package-commands.js +15 -4
  17. package/dist/runtime/sdk-source.d.ts +2 -0
  18. package/dist/runtime/sdk-source.js +2 -0
  19. package/dist/spk/archive-inventory.d.ts +9 -0
  20. package/dist/spk/archive-inventory.js +65 -0
  21. package/dist/spk/check-payload.js +9 -0
  22. package/dist/spk/rules.d.ts +5 -0
  23. package/dist/spk/rules.js +1 -0
  24. package/dist/spk/validate-spk.js +12 -0
  25. package/dist/standalone/compose.js +4 -4
  26. package/dist/standalone/daemon-ingress.d.ts +3 -2
  27. package/dist/standalone/daemon-ingress.js +12 -9
  28. package/dist/standalone/daemon-restart.d.ts +1 -1
  29. package/dist/standalone/daemon-restart.js +3 -3
  30. package/dist/standalone/daemon.d.ts +2 -2
  31. package/dist/standalone/daemon.js +5 -5
  32. package/dist/standalone/inspect-bridge.d.ts +3 -1
  33. package/dist/standalone/inspect-bridge.js +6 -3
  34. package/dist/standalone/inspect-spk.js +27 -7
  35. package/dist/standalone/install-settings.js +2 -2
  36. package/dist/standalone/manifest.js +1 -1
  37. package/dist/standalone/native-layout.js +18 -1
  38. package/dist/template-paths.d.ts +0 -4
  39. package/dist/template-paths.js +0 -11
  40. package/docs/ctl-external.md +16 -0
  41. package/package.json +3 -2
  42. package/skills/SKILL.md +1 -1
  43. package/skills/reference/ctl.md +24 -0
  44. package/skills/reference/daemon-mode.md +5 -0
  45. 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
  }
@@ -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;
@@ -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
- }
@@ -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.41.12",
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.35.5",
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.35.5`. A templates patch needs only a
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
@@ -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.38.6, CLI 0.41.12 and templates 0.35.5. Configure installation through the manifest and generated wizard; do not add App ACL writers, root hooks or independent port state.
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: