@synopackageland/cli 0.7.0 → 0.7.2

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 (165) hide show
  1. package/CHANGELOG.md +301 -1
  2. package/assets/default-icon/README.md +19 -0
  3. package/assets/default-icon/default-icon-small.svg +9 -0
  4. package/assets/default-icon/default-icon.svg +10 -0
  5. package/assets/default-icon/icon_16.png +0 -0
  6. package/assets/default-icon/icon_24.png +0 -0
  7. package/assets/default-icon/icon_256.png +0 -0
  8. package/assets/default-icon/icon_32.png +0 -0
  9. package/assets/default-icon/icon_48.png +0 -0
  10. package/assets/default-icon/icon_64.png +0 -0
  11. package/assets/default-icon/icon_72.png +0 -0
  12. package/dist/add.d.ts +4 -1
  13. package/dist/add.js +14 -9
  14. package/dist/build-spk/dsm-icons.d.ts +31 -2
  15. package/dist/build-spk/dsm-icons.js +135 -56
  16. package/dist/build-spk/dsm-platforms.json +4 -1
  17. package/dist/build-spk/gateway.d.ts +1 -1
  18. package/dist/build-spk/gateway.js +8 -4
  19. package/dist/build-spk/generator.js +17 -3
  20. package/dist/build-spk/go-toolchain.d.ts +20 -0
  21. package/dist/build-spk/go-toolchain.js +44 -0
  22. package/dist/build-spk/png.d.ts +14 -0
  23. package/dist/build-spk/png.js +161 -0
  24. package/dist/build-spk/ui-texts.d.ts +20 -0
  25. package/dist/build-spk/ui-texts.js +42 -0
  26. package/dist/cli.js +39 -9
  27. package/dist/contract/i18n.d.ts +5 -0
  28. package/dist/contract/i18n.js +45 -0
  29. package/dist/contract/icon.d.ts +5 -0
  30. package/dist/contract/icon.js +27 -0
  31. package/dist/contract/validate.js +4 -0
  32. package/dist/contract/web-launch.js +6 -2
  33. package/dist/deploy/native-install-values.d.ts +17 -0
  34. package/dist/deploy/native-install-values.js +32 -0
  35. package/dist/deploy/plan.d.ts +6 -2
  36. package/dist/deploy/plan.js +57 -6
  37. package/dist/error-registry.js +15 -6
  38. package/dist/host/dsm-client.js +53 -17
  39. package/dist/host/dsm-http.js +24 -2
  40. package/dist/host/types.d.ts +1 -0
  41. package/dist/info.js +28 -9
  42. package/dist/init.js +1 -1
  43. package/dist/runtime/dsm-version.d.ts +6 -0
  44. package/dist/runtime/dsm-version.js +8 -0
  45. package/dist/runtime/executor-build.d.ts +1 -1
  46. package/dist/runtime/executor-build.js +8 -5
  47. package/dist/standalone/daemon.d.ts +2 -1
  48. package/dist/standalone/daemon.js +10 -6
  49. package/dist/standalone/dsm-window.d.ts +2 -0
  50. package/dist/standalone/dsm-window.js +26 -40
  51. package/dist/standalone/i18n.d.ts +12 -0
  52. package/dist/standalone/i18n.js +30 -0
  53. package/dist/standalone/inspect-spk.d.ts +5 -0
  54. package/dist/standalone/inspect-spk.js +41 -2
  55. package/dist/standalone/manifest.d.ts +5 -6
  56. package/dist/standalone/manifest.js +21 -34
  57. package/dist/standalone/native-authorization-window.d.ts +1 -1
  58. package/dist/standalone/native-authorization-window.js +7 -1
  59. package/dist/standalone/native-layout.d.ts +2 -0
  60. package/dist/standalone/native-layout.js +22 -1
  61. package/dist/standalone/native-root-window.d.ts +4 -2
  62. package/dist/standalone/native-root-window.js +33 -18
  63. package/dist/standalone/root-window.d.ts +4 -1
  64. package/dist/standalone/root-window.js +143 -33
  65. package/dist/standalone/spk.js +7 -4
  66. package/dist/templates/_daemon/go.mod +1 -1
  67. package/dist/templates/_daemon/main.go +6 -3
  68. package/dist/templates/_daemon/main_test.go +21 -1
  69. package/dist/templates/_daemon/testdata/child.go +3 -0
  70. package/dist/templates/_executor/README.md +4 -1
  71. package/dist/templates/_executor/anchor.go +10 -0
  72. package/dist/templates/_executor/anchor_test.go +40 -5
  73. package/dist/templates/_executor/digest_review_test.go +2 -2
  74. package/dist/templates/_executor/dsm.go +40 -3
  75. package/dist/templates/_executor/go.mod +2 -0
  76. package/dist/templates/_executor/main.go +11 -5
  77. package/dist/templates/_executor/managed.go +3 -3
  78. package/dist/templates/_executor/managed_test.go +3 -3
  79. package/dist/templates/_executor/path_test.go +18 -0
  80. package/dist/templates/_executor/pid.go +37 -0
  81. package/dist/templates/_executor/pid_test.go +113 -0
  82. package/dist/templates/_executor/platform_other.go +8 -0
  83. package/dist/templates/_executor/purge_log.go +18 -0
  84. package/dist/templates/_executor/tasks.go +45 -7
  85. package/dist/templates/_executor/tasks_dsm71_test.go +114 -0
  86. package/dist/templates/_executor/tasks_test.go +58 -1
  87. package/dist/templates/_executor/upgrade_watch_test.go +13 -5
  88. package/dist/templates/_gateway/go.mod +2 -0
  89. package/dist/templates/binary/dsm-package.yaml +3 -0
  90. package/dist/templates/compose/synology-app.yaml +3 -0
  91. package/dist/templates/native-go/backend/go.mod +1 -1
  92. package/dist/templates/native-go/backend/internal/filestation/client.go +39 -3
  93. package/dist/templates/native-go/backend/internal/filestation/download_dsm71_test.go +82 -0
  94. package/dist/templates/native-go/backend/internal/identity/README.md +5 -1
  95. package/dist/templates/native-go/backend/internal/identity/dsm.go +24 -5
  96. package/dist/templates/native-go/backend/internal/identity/http.go +1 -1
  97. package/dist/templates/native-go/backend/internal/identity/identity_test.go +48 -1
  98. package/dist/templates/native-go/backend/internal/identity/service.go +1 -1
  99. package/dist/templates/native-go/dsm-package.yaml +3 -0
  100. package/dist/templates/native-go-delegate/frontend/test/delegate.test.ts +15 -0
  101. package/dist/templates/native-go-root-ops/backend/internal/app/executor.go +30 -2
  102. package/dist/templates/native-go-root-ops/backend/internal/app/executor_test.go +64 -0
  103. package/dist/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +3 -2
  104. package/dist/templates/native-go-vue/frontend/src/delegate/executor-settings.test.ts +23 -0
  105. package/dist/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +5 -1
  106. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/de.json +1 -0
  107. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/en.json +1 -0
  108. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/es.json +1 -0
  109. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +1 -0
  110. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/it.json +1 -0
  111. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +1 -0
  112. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +1 -0
  113. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +1 -0
  114. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +1 -0
  115. package/package.json +2 -1
  116. package/schema/synology-app.schema.json +22 -0
  117. package/templates/_daemon/go.mod +1 -1
  118. package/templates/_daemon/main.go +6 -3
  119. package/templates/_daemon/main_test.go +21 -1
  120. package/templates/_daemon/testdata/child.go +3 -0
  121. package/templates/_executor/README.md +4 -1
  122. package/templates/_executor/anchor.go +10 -0
  123. package/templates/_executor/anchor_test.go +40 -5
  124. package/templates/_executor/digest_review_test.go +2 -2
  125. package/templates/_executor/dsm.go +40 -3
  126. package/templates/_executor/go.mod +2 -0
  127. package/templates/_executor/main.go +11 -5
  128. package/templates/_executor/managed.go +3 -3
  129. package/templates/_executor/managed_test.go +3 -3
  130. package/templates/_executor/path_test.go +18 -0
  131. package/templates/_executor/pid.go +37 -0
  132. package/templates/_executor/pid_test.go +113 -0
  133. package/templates/_executor/platform_other.go +8 -0
  134. package/templates/_executor/purge_log.go +18 -0
  135. package/templates/_executor/tasks.go +45 -7
  136. package/templates/_executor/tasks_dsm71_test.go +114 -0
  137. package/templates/_executor/tasks_test.go +58 -1
  138. package/templates/_executor/upgrade_watch_test.go +13 -5
  139. package/templates/_gateway/go.mod +2 -0
  140. package/templates/binary/dsm-package.yaml +3 -0
  141. package/templates/compose/synology-app.yaml +3 -0
  142. package/templates/native-go/backend/go.mod +1 -1
  143. package/templates/native-go/backend/internal/filestation/client.go +39 -3
  144. package/templates/native-go/backend/internal/filestation/download_dsm71_test.go +82 -0
  145. package/templates/native-go/backend/internal/identity/README.md +5 -1
  146. package/templates/native-go/backend/internal/identity/dsm.go +24 -5
  147. package/templates/native-go/backend/internal/identity/http.go +1 -1
  148. package/templates/native-go/backend/internal/identity/identity_test.go +48 -1
  149. package/templates/native-go/backend/internal/identity/service.go +1 -1
  150. package/templates/native-go/dsm-package.yaml +3 -0
  151. package/templates/native-go-delegate/frontend/test/delegate.test.ts +15 -0
  152. package/templates/native-go-root-ops/backend/internal/app/executor.go +30 -2
  153. package/templates/native-go-root-ops/backend/internal/app/executor_test.go +64 -0
  154. package/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +3 -2
  155. package/templates/native-go-vue/frontend/src/delegate/executor-settings.test.ts +23 -0
  156. package/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +5 -1
  157. package/templates/native-go-vue/frontend/src/delegate/i18n/de.json +1 -0
  158. package/templates/native-go-vue/frontend/src/delegate/i18n/en.json +1 -0
  159. package/templates/native-go-vue/frontend/src/delegate/i18n/es.json +1 -0
  160. package/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +1 -0
  161. package/templates/native-go-vue/frontend/src/delegate/i18n/it.json +1 -0
  162. package/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +1 -0
  163. package/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +1 -0
  164. package/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +1 -0
  165. package/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +1 -0
package/CHANGELOG.md CHANGED
@@ -1,6 +1,306 @@
1
1
  # Changelog
2
2
 
3
- ## Unreleased
3
+ ## 0.7.2 (2026-10-11)
4
+
5
+ Rebuild packages to pick up the new default icon. Packages without `icon` now
6
+ show the SDK default icon instead of a solid blue square.
7
+
8
+ ### Package icon
9
+
10
+ - `dsm-package.yaml` and `synology-app.yaml` accept `icon`: a square PNG of at
11
+ least 256×256 inside the project, or a folder of `icon_<size>.png` (16, 24,
12
+ 32, 48, 64, 72, 256; `icon_256.png` required, missing sizes scaled from it).
13
+ `build` writes `PACKAGE_ICON.PNG` (64×64), `PACKAGE_ICON_256.PNG` and every
14
+ DSM window size `ui/images/app_<size>.png` from it. SVG is not accepted, so
15
+ the CLI gains no image dependency. `check` refuses an icon outside the
16
+ project, a non-PNG, a non-square or smaller image, and one whose Package
17
+ Center icons exceed the package source's 256 KiB limit
18
+ (`STANDALONE_ICON_INVALID`, `CONTRACT_ICON_INVALID`).
19
+
20
+ - A native layout may set `icon` too; `build` then writes both Package Center
21
+ icons and refuses a metadata folder that also ships them. Without `icon` the
22
+ layout keeps owning its icons.
23
+
24
+ - `check` reports which icon a build uses: `圖示:自訂 <path>`, or `圖示:SDK
25
+ 預設圖示` with an info hint about `icon:` (not an error). It warns when an
26
+ icon is a single colour. `check --json` reports it in `data.icon`.
27
+
28
+ - `inspect` reports `icon` as `default`, `custom` (with the SHA-256 of
29
+ `PACKAGE_ICON_256.PNG`) or `none`, and lists a Package Center icon over
30
+ 256 KiB, of the wrong size or not a PNG as a finding.
31
+
32
+ - The SDK default icon replaces the solid blue square in Package Center, the
33
+ DSM main menu and the window. Sources are in `assets/default-icon/`.
34
+
35
+ ### Translated DSM title
36
+
37
+ - With `i18n.info` translations, the DSM main-menu entry and window title
38
+ follow the DSM language. `ui/config` refers to `synopkgland:app_title` and
39
+ `app_desc` in `ui/texts/<DSM language>/strings`, written for English and each
40
+ translated language; a language without its own text shows the English one.
41
+ Without translations `ui/config` keeps the literal English title.
42
+
43
+ - `synology-app.yaml` accepts the same `i18n.info` block. It writes INFO
44
+ `displayname_<lang>` / `description_<lang>` and, with `launch: dsm-window`,
45
+ localizes the DSM window entry. Once a translation exists, the English
46
+ `displayname` and `description` must also be one line without `"` or `\`
47
+ (`CONTRACT_I18N_INVALID`).
48
+
49
+ ### Delegate window
50
+
51
+ - A DSM window built for a `scope: install-selected` delegate no longer
52
+ contains the dead `if (panels && false)` check. The window leaves out the
53
+ approval panel code instead, and other scopes generate `if (panels)`. The
54
+ behavior is unchanged: this scope is approved only in the app's
55
+ **Administrator setup** panel, because that approval carries the scope the
56
+ administrator picks and the window panel has no scope picker. The delegate
57
+ guide now says so.
58
+
59
+ ### 繁體中文摘要
60
+
61
+ - 升級後重新建置套件即可換上新的 SDK 預設圖示(不再是純藍方塊)。executor digest 不變,不需重新核准。
62
+ - `dsm-package.yaml`、`synology-app.yaml` 與 native layout 新增 `icon`:專案內至少 256×256 的正方形
63
+ PNG,或含 `icon_256.png` 的 `icon_<size>.png` 目錄;不接受 SVG。`check` 顯示使用的圖示並檢查格式與
64
+ 256 KiB 上限,`inspect` 回報 `default`/`custom`/`none`。
65
+ - 有 `i18n.info` 翻譯時,DSM 主選單與視窗標題會跟著 DSM 語言切換;缺翻譯的語言顯示英文。
66
+ `synology-app.yaml` 也支援 `i18n.info`。
67
+ - `scope: install-selected` 的 DSM 視窗不再產生 `if (panels && false)` 死碼;此 scope 仍只在 App 的
68
+ 「管理員設定」核准。
69
+
70
+ ## 0.7.1 (2026-10-10)
71
+
72
+ Rebuild packages to pick up template, hook and executor changes. The executor
73
+ digest changed. A package built with CLI 0.7.0 needs one administrator approval
74
+ after upgrading to a 0.7.1 build: the 0.7.0 executor opened the package
75
+ `target` link without following it, so it cannot install the anchored executor
76
+ itself. Executor-only upgrades between 0.7.1 or later builds need no approval.
77
+
78
+ ### Executor upgrade and daemon timeouts
79
+
80
+ - During an INFO-anchored executor-only upgrade the executor log said
81
+ `executor paused: package pins require administrator approval` about two
82
+ seconds before the new executor was ready. That line now appears only when
83
+ the pins differ; an anchored handover logs only `executor upgrade:
84
+ INFO-anchored executor installed under the approved policy`. The executor
85
+ digest changes.
86
+
87
+ - `executor_status_mismatch` in the app window and the app's settings names
88
+ its cause: `the approved executor is not answering (<reason>)`, `the running
89
+ executor reports other digests than this package pins`, or `the executor
90
+ status request failed` with the request's own code, instead of `scheduler
91
+ readback or operation failed` for all three. The Data and removal
92
+ troubleshooting table explains each.
93
+
94
+ - After approval or control start the window asked `executor.status` every
95
+ 500 ms for up to 10 s. The wait now doubles from 500 ms to 2 s within the
96
+ same 10 s budget: at most 7 requests instead of 20.
97
+
98
+ - For live upgrade tests, the repository's `scripts/test/executor-bump.py`
99
+ makes an executor-only build+1 SPK and now rewrites the window script's
100
+ embedded pins with the INFO anchor and `executor/setup.json`. The earlier
101
+ out-of-tree copy left the window pins behind, so the panel reported
102
+ `executor_status_mismatch` after every such upgrade while CGI and CLI
103
+ status were ready.
104
+
105
+ - On kernel 3.10 (DSM 7.1, for example DS416 armv7) an executor-only
106
+ upgrade, and approving again while the executor runs, no longer fail
107
+ with "pid executable mismatch". That kernel names a running executor
108
+ replaced by a rename after the rename source (`runtime/.executor
109
+ (deleted)`), and root control accepted only `runtime/executor`. Root
110
+ control now identifies the monitor by inode: the current
111
+ `runtime/executor`, or an unlinked root-owned inode on the runtime's
112
+ device whose last name was `executor` or `.executor*` in the runtime.
113
+ The fix runs in the new executor, which the installed one starts: an
114
+ upgrade from a package built with the target-link fix below needs no
115
+ approval; from 0.7.0 it still needs the one approval described there.
116
+ The executor digest changes.
117
+
118
+ - When the approved tasks are ready but the executor does not answer
119
+ (`executor_status_mismatch`), the app window offers Approve background
120
+ access again. With the tasks approved, it restarts the executor without
121
+ a password.
122
+
123
+ - `executor.status` (root-ops) names approval, not "Start the package", as
124
+ the next step when the package's last lifecycle request was start.
125
+ Regenerate or copy `backend/internal/app/executor.go`.
126
+
127
+ - An executor-only upgrade (same policy, new executor matching the INFO
128
+ `synopkgland_executor_sha256` anchor) no longer fails with "executor
129
+ upgrade refused: INFO-anchored executor could not be installed". The
130
+ installer opened `/var/packages/<pkg>/target/executor` without following
131
+ the DSM `target` link, which the executor refuses, so every such upgrade
132
+ stayed paused. The fix runs in the executor that is already installed:
133
+ an upgrade from a package built with an earlier SDK still needs one
134
+ administrator approval. The executor digest changes.
135
+
136
+ - `executor.status` (root-ops and delegate projects) no longer answers
137
+ `internal` while the executor is paused (package stopped, or pins waiting
138
+ for approval). It answers `{ready: false, state: "paused", reason:
139
+ "executor_not_listening", next}`, and `synopkgland status` shows the
140
+ reason and next step. Regenerate or copy
141
+ `backend/internal/app/executor.go` into existing projects.
142
+
143
+ - `daemon.timeouts` defaults are now `{start: 30, stop: 30, status: 5,
144
+ uninstall: 60}` (were `start: 5, stop: 10, status: 2`). On vt-nas under
145
+ IO load a boot start took more than 5 s and a Connect revoke more than
146
+ 9 s. The new `timeouts.uninstall` (2–120) bounds `uninstall_args`
147
+ separately; it used to get `stop - 1`, so an app had to raise the SIGKILL
148
+ wait to give its revoke time. DSM's package unit allows 3600 s for start
149
+ and stop. `inspect` still accepts SPKs built before `timeouts.uninstall`.
150
+ The manifest reference explains how to pick values from a loaded NAS.
151
+
152
+ ### Approval, identity and uninstall fixes
153
+
154
+ - `identity: standalone`: "Continue with DSM" and every live revalidation
155
+ failed with `session_required` after a DSM web login, because DSM web
156
+ sessions enable SynoToken and DSM answers the `id` cookie alone with 119.
157
+ The backend now forwards the request's single `X-SYNO-TOKEN` header, which
158
+ the DSM window's `ctx.call` already sends, when it checks the DSM session.
159
+ Sessions without SynoToken still verify with the cookie alone. The token is
160
+ never put in a URL, logged or stored. This also unblocks root-ops approval
161
+ in an `identity: standalone` package, which stopped at `executor.control`.
162
+ Existing projects need the updated `internal/identity` files.
163
+ - When approval created and read back both tasks but the executor then did
164
+ not start or report healthy, the window left the tasks behind, and with no
165
+ running executor there was no task inventory for uninstall to delete them.
166
+ The window now withdraws the tasks that approval created; tasks from an
167
+ earlier approval stay.
168
+ - After a wrong password or a withdrawn approval, the window panel showed
169
+ only "Check status". It and the app's settings now keep the approve action.
170
+ - Uninstall no longer logs `task cleanup unconfirmed` for every successful
171
+ delete: EventScheduler `delete` v1 and TaskScheduler `delete` v2 answer
172
+ `{"success":true}` without data, which now counts as confirmed. The task
173
+ definitions are unchanged, so no new approval is needed; the executor
174
+ digest changes.
175
+ - The native root window (`@synopackageland/cli/authorization-sdk`) gave up
176
+ after about 30 s with `root_timeout`, while a loaded NAS ran the bootstrap
177
+ task for up to 4.5 minutes. It now keeps waiting while the task is queued or
178
+ running, up to 10 minutes, reports `{op, state, elapsedMs}` through
179
+ `options.progress`, and the authorization flow accepts the backend's ready
180
+ grant after `root_timeout` or `root_task_failed`.
181
+ - A DSM certificate that Node does not trust failed with only
182
+ `fetch failed`. The CLI now reports `DSM_TLS_UNTRUSTED` with the origin and
183
+ certificate error and points to `NODE_EXTRA_CA_CERTS`; certificate checks
184
+ stay on.
185
+ - Docs: on DSM 7.1 the purge timing lines are only in the journal
186
+ (`journalctl -t synopkgland-executor`); `init -t native-go` does not include
187
+ `armv7` in `arches`, so add it for an armv7 NAS.
188
+
189
+ ### Deploy and status fixes
190
+
191
+ - `status` no longer reports `blocked` for every `identity: standalone`
192
+ project. It opens a short-lived App session from the administrator's DSM
193
+ session, reads `executor.status`, then logs out. That needs an `https://`
194
+ host; over `http://` the capability stays `blocked` and the reason says so.
195
+ - `deploy` accepts the install wizard values of an `install-selected`
196
+ delegate: `--param delegate_share=<Shared Folder>` or
197
+ `--param delegate_home=true`. A first install without one now fails with
198
+ `DEPLOY_PARAM_REQUIRED` and a usage line before anything is built, instead
199
+ of failing inside DSM. Invalid values fail with `DEPLOY_PARAM_TYPE_INVALID`.
200
+ - `deploy` and `status` work on a native layout (existing native product).
201
+ `deploy` builds the NAS architecture only; an `aarch64` NAS uses a declared
202
+ `armv8`.
203
+ - The deploy note no longer says every upgrade needs approval: an
204
+ executor-only upgrade stays ready; a policy digest change needs approval.
205
+ - Uninstall logs per-phase purge timing with the package name to the system
206
+ log (`synopkgland-executor`): `task cleanup timing` per task and
207
+ `purge timing` for the task and file phases. The executor digest changes.
208
+ - `add root-ops` and `add portal` print a notice on stderr when they raise
209
+ `os_min_ver`.
210
+ - `inspect` on an executor SPK describes the root boot and control tasks
211
+ instead of saying the package needs no root privileges.
212
+
213
+ ### DSM 7.1: root-ops and delegate approval work
214
+
215
+ - DSM 7.1.1 has no `SYNO.Core.TaskScheduler.Root` or
216
+ `SYNO.Core.EventScheduler.Root`, TaskScheduler stops at v3 and
217
+ PasswordConfirm at v1, so approval failed with "Background file access is
218
+ unavailable" and `status`/`deploy` showed `rootOps: unsupported — DSM 103`
219
+ or `DSM 104`. DSM 7.1.1 answers a version above the API's maximum with 104
220
+ (PasswordConfirm v2, TaskScheduler `get` v4) and a method missing at an
221
+ existing version with 103 (TaskScheduler `list` v3). When DSM answers a
222
+ scheduler read or the password check with 103 or 104, the app now uses
223
+ PasswordConfirm v1, TaskScheduler `list` v2/`get` v3 and creates
224
+ the tasks with EventScheduler `create` v1 and TaskScheduler `create` v3.
225
+ The password is still confirmed first and both tasks are still read back
226
+ exactly before anything runs. Other errors (such as 105, 119, 102 or a
227
+ wrong password, 3121) never fall back, and a create is never retried. DSM
228
+ 7.1 does not bind task creation to the password check; see the root-ops
229
+ guide.
230
+ - `status` and `deploy` read the control task the same way.
231
+ - Uninstall on DSM 7.1 now removes the boot and control tasks. The executor
232
+ looked the control task up with TaskScheduler `get` v4, which DSM 7.1.1
233
+ refuses with 104, so it wrote no task inventory and left both tasks behind.
234
+ - If approval stops after it created a task (for example, the boot task was
235
+ created and the control task was not), the app deletes the tasks it created
236
+ in that attempt instead of leaving an enabled root boot task that nothing
237
+ owns. Tasks from an earlier approval stay.
238
+ - A failed approval shows its reason and DSM error code in the app's settings
239
+ instead of only "Background file access is unavailable", and a refused
240
+ password reads as a password failure, not a scheduler failure.
241
+ - After the app's settings approve, the window's status line no longer shows
242
+ "needs-admin-approval: Task is missing" until a reload; the window panel and
243
+ the settings now follow each other's results.
244
+
245
+ ### DSM 7.1: jobs import and file downloads
246
+
247
+ - DSM 7.1.1 sends `SYNO.FileStation.Download` v2 replies without
248
+ `Content-Disposition`, so `bg.jobs.submit` and downloads failed with
249
+ `unavailable`. With no such header, a body of at most 4 KiB that decodes
250
+ as a DSM reply is still refused as that reply; any other body is the file.
251
+
252
+ ### Docs: build your own armv7 Go code with Go 1.26.9
253
+
254
+ - On armv7 DSM 7.1.1 (kernel 3.10), a program built with Go 1.26.0 crashed
255
+ at start (`futexwakeup returned -22`, SIGSEGV) and Go 1.26.9 ran. Other
256
+ 1.26 releases were not tested.
257
+
258
+ ### init: next steps install frontend dependencies
259
+
260
+ - `init -t native-go` with a Vue frontend now lists `(cd frontend && npm ci)`
261
+ before `synopkgland build`; without it the build fails with
262
+ `STANDALONE_UI_BUILD_FAILED`. `build` still does not install dependencies.
263
+
264
+ ### Executor, daemon and gateway build with exactly Go 1.26.9
265
+
266
+ - The CLI builds the executor, lifecycle helper, daemon controller and gateway
267
+ with `GOTOOLCHAIN=go1.26.9`, ignoring your `GOTOOLCHAIN`, `GOFLAGS`,
268
+ `GOEXPERIMENT`, `GOWORK` and `GOAMD64`/`GOARM64`, so every builder produces
269
+ the same executor digest. Go 1.21 or later downloads go1.26.9 when needed;
270
+ offline without it the build fails and names go1.26.9. A binary whose Go
271
+ build info names another release is refused.
272
+ - Template go.mod files now say `toolchain go1.26.9`. The executor digest
273
+ changes; it is anchored in INFO, so an upgrade with an unchanged policy needs
274
+ no new approval.
275
+
276
+ ### INFO arch: four more DSM platforms
277
+
278
+ - x86_64 SPKs now also list `broadwellntb`, `coffeelake` and `skylaked`, and
279
+ aarch64 SPKs list `rtd1619` (DSM Developer Guide Appendix A family members).
280
+ INFO `arch` now matches the platforms the package source maps to each family.
281
+
282
+ ### 繁體中文摘要
283
+
284
+ - 升級後重新建置套件;executor digest 改變。**從 0.7.0 建的套件升級需管理員再核准一次**(0.7.0 的
285
+ executor 開啟套件 `target` symlink 時未跟隨連結,無法自行安裝錨定的 executor);之後 0.7.1 起的
286
+ executor-only 升級不需核准。
287
+ - executor:kernel 3.10(DSM 7.1,如 DS416 armv7)上 executor-only 升級與執行中再核准不再出現
288
+ `pid executable mismatch`;INFO 錨定升級不再誤報 `executor upgrade refused`,也不再先印
289
+ 「paused: 需管理員核准」;`executor.status` 暫停時回 `paused`/`executor_not_listening` 與下一步。
290
+ - 面板:executor 不回應時可再按一次「Approve background access」免密碼重啟;
291
+ `executor_status_mismatch` 會寫出原因(不回應/digest 不同/status 請求失敗);
292
+ 啟動後的 `executor.status` 等待改為 500 ms→2 s 退避,10 s 預算不變。
293
+ - `daemon.timeouts` 預設改為 `{start: 30, stop: 30, status: 5, uninstall: 60}`,新增 `timeouts.uninstall`。
294
+ - `identity: standalone`:DSM 網頁 session(SynoToken)下「Continue with DSM」與 root-ops 核准修正;
295
+ 核准建立 task 後 executor 未啟動時自動撤回本次建立的 task;卸載不再誤記 `task cleanup unconfirmed`。
296
+ - 原生 root window 等待上限改為 10 分鐘並回報進度;`DSM_TLS_UNTRUSTED` 指向 `NODE_EXTRA_CA_CERTS`。
297
+ - `status`/`deploy`:standalone 專案的 status 改用短期 App session;`deploy` 接受
298
+ install-selected delegate 的精靈參數;支援 native layout;卸載記錄 purge timing。
299
+ - DSM 7.1:無 Root API 時改走 PasswordConfirm v1/TaskScheduler v2–v3/EventScheduler create v1,
300
+ 卸載會移除 boot/control task;`SYNO.FileStation.Download` v2 無 `Content-Disposition` 的下載修正。
301
+ - 建置:executor、lifecycle、daemon、gateway 一律以 Go 1.26.9 建置(armv7 kernel 3.10 上 1.26.0 會當機);
302
+ INFO `arch` 新增 `broadwellntb`、`coffeelake`、`skylaked`、`rtd1619`。
303
+ - 測試工具:`scripts/test/executor-bump.py` 收進 repo,會一併改寫視窗腳本內嵌的 executor pin。
4
304
 
5
305
  ## 0.7.0 (2026-10-10)
6
306
 
@@ -0,0 +1,19 @@
1
+ # SDK default package icon
2
+
3
+ Used by `synopkgland build` when `dsm-package.yaml` or `synology-app.yaml`
4
+ sets no `icon`. It marks an App that has not chosen its own icon yet: a
5
+ Package Land parcel on the cream brand tile, not a broken image.
6
+
7
+ This folder is itself an icon directory (`icon: <dir>`): `icon_<size>.png`
8
+ files are used as drawn and `icon_256.png` is scaled for any missing size.
9
+
10
+ - `default-icon.svg` draws 48, 64, 72 and 256.
11
+ - `default-icon-small.svg` is a 16 px pixel grid for 16, 24 and 32.
12
+
13
+ Regenerate after editing an SVG (rsvg-convert is a maintainer tool only;
14
+ the CLI never rasterises SVG):
15
+
16
+ ```sh
17
+ for s in 16 24 32; do rsvg-convert -w $s -h $s default-icon-small.svg -o icon_$s.png; done
18
+ for s in 48 64 72 256; do rsvg-convert -w $s -h $s default-icon.svg -o icon_$s.png; done
19
+ ```
@@ -0,0 +1,9 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" shape-rendering="crispEdges">
2
+ <rect x="0" y="0" width="16" height="16" rx="3.5" fill="#fbf5e8"/>
3
+ <rect x="3" y="2" width="2" height="2" fill="#1f78e5"/>
4
+ <rect x="7" y="1" width="2" height="3" fill="#f6b324"/>
5
+ <rect x="11" y="2" width="2" height="2" fill="#1f78e5"/>
6
+ <rect x="2" y="4" width="12" height="3" fill="#135bb8"/>
7
+ <rect x="3" y="7" width="10" height="7" fill="#1f78e5"/>
8
+ <rect x="6" y="9" width="4" height="1" fill="#fbf5e8"/>
9
+ </svg>
@@ -0,0 +1,10 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 256 256">
2
+ <rect x="6" y="6" width="244" height="244" rx="56" fill="#fbf5e8" stroke="#e4d8bd" stroke-width="4"/>
3
+ <path d="M212 22l6 14 14 6-14 6-6 14-6-14-14-6 14-6z" fill="#f6b324"/>
4
+ <rect x="62" y="58" width="30" height="30" rx="6" fill="#1f78e5"/>
5
+ <rect x="113" y="50" width="30" height="38" rx="6" fill="#f6b324"/>
6
+ <rect x="164" y="58" width="30" height="30" rx="6" fill="#1f78e5"/>
7
+ <rect x="48" y="80" width="160" height="44" rx="12" fill="#135bb8"/>
8
+ <path d="M58 118h140v66a24 24 0 0 1-24 24H82a24 24 0 0 1-24-24z" fill="#1f78e5"/>
9
+ <rect x="100" y="140" width="56" height="16" rx="8" fill="#fbf5e8"/>
10
+ </svg>
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/dist/add.d.ts CHANGED
@@ -1,4 +1,7 @@
1
- export declare function addCapabilities(root: string, requested: string[]): {
1
+ type AddResult = {
2
2
  added: string[];
3
3
  unchanged: string[];
4
+ notes?: string[];
4
5
  };
6
+ export declare function addCapabilities(root: string, requested: string[]): AddResult;
7
+ export {};
package/dist/add.js CHANGED
@@ -46,11 +46,17 @@ function safePath(root, file) {
46
46
  }
47
47
  return true;
48
48
  }
49
- /** Raise a lower os_min_ver to the floor a capability needs; a higher one stays. */
50
- function raiseOsMinVer(doc, current, floor) {
49
+ /** Raise a lower os_min_ver to the floor a capability needs; a higher one stays. Returns the notice. */
50
+ function raiseOsMinVer(doc, current, floor, capability) {
51
51
  const osMinVer = doc.get('os_min_ver', true);
52
- if (isScalar(osMinVer) && !isDsmAtLeast(current, floor))
53
- osMinVer.value = floor;
52
+ if (!isScalar(osMinVer) || isDsmAtLeast(current, floor))
53
+ return [];
54
+ osMinVer.value = floor;
55
+ return [`os_min_ver raised from ${current} to ${floor}: ${capability} needs DSM ${floor} or later.`];
56
+ }
57
+ function withNotes(result, notes) {
58
+ const all = [...(result.notes ?? []), ...notes];
59
+ return all.length ? { ...result, notes: all } : result;
54
60
  }
55
61
  /**
56
62
  * `portal: {}` in dsm-package.yaml; the Go and binary starters already carry the UI and backend side.
@@ -67,9 +73,9 @@ function addPortal(root, result) {
67
73
  const manifestPath = join(root, 'dsm-package.yaml');
68
74
  const doc = parseDocument(readFileSync(manifestPath, 'utf8'));
69
75
  doc.set('portal', doc.createNode({}, { flow: true }));
70
- raiseOsMinVer(doc, loaded.manifest.os_min_ver, PORTAL_MIN_DSM);
76
+ const notes = raiseOsMinVer(doc, loaded.manifest.os_min_ver, PORTAL_MIN_DSM, 'portal');
71
77
  writeFileSync(manifestPath, String(doc));
72
- return { ...result, added: [...result.added, 'portal'] };
78
+ return withNotes({ ...result, added: [...result.added, 'portal'] }, notes);
73
79
  }
74
80
  export function addCapabilities(root, requested) {
75
81
  const wanted = [...new Set(requested.flatMap(value => value.split(',')).map(value => value.trim()))];
@@ -129,8 +135,7 @@ export function addCapabilities(root, requested) {
129
135
  for (const [key, value] of Object.entries(nativeCapabilitySettings(added)))
130
136
  doc.setIn(['capabilities', key], value);
131
137
  // rootOps needs DSM 7.1-42661 or later.
132
- if (added.includes('root-ops'))
133
- raiseOsMinVer(doc, m.os_min_ver, DEFAULT_MIN_DSM);
138
+ const notes = added.includes('root-ops') ? raiseOsMinVer(doc, m.os_min_ver, DEFAULT_MIN_DSM, 'root-ops') : [];
134
139
  for (const file of destinations) {
135
140
  const path = join(root, file);
136
141
  mkdirSync(dirname(path), { recursive: true });
@@ -139,7 +144,7 @@ export function addCapabilities(root, requested) {
139
144
  for (const file of deletions)
140
145
  rmSync(join(root, file), { force: true });
141
146
  writeFileSync(manifestPath, String(doc));
142
- return { added, unchanged };
147
+ return withNotes({ added, unchanged }, notes);
143
148
  }
144
149
  finally {
145
150
  rmSync(work, { recursive: true, force: true });
@@ -1,2 +1,31 @@
1
- export declare function writeDsmWindowIcons(uiDir: string): void;
2
- export declare function writePackageCenterIcons(spkRoot: string): void;
1
+ /** Sizes DSM loads for `images/app_{0}.png` (main menu, desktop, window, taskbar). */
2
+ export declare const WINDOW_ICON_SIZES: readonly [16, 24, 32, 48, 64, 72, 256];
3
+ /** The package source drops a release whose PACKAGE_ICON is larger than this. */
4
+ export declare const MAX_ICON_BYTES: number;
5
+ export interface PackageIcons {
6
+ source: "custom" | "default";
7
+ /** Encoded PNG per DSM window size; PACKAGE_ICON.PNG is 64 and PACKAGE_ICON_256.PNG is 256. */
8
+ window: Map<number, Buffer>;
9
+ packageIcon: Buffer;
10
+ packageIcon256: Buffer;
11
+ /** Every pixel of the 256 px icon is the same colour. */
12
+ solid: boolean;
13
+ }
14
+ /** Ships next to dist/ and src/ alike: <package>/assets/default-icon. */
15
+ export declare const DEFAULT_ICON_DIR: string;
16
+ /** A project icon: one square PNG of at least 256 px, or a directory of icon_<size>.png. */
17
+ export declare function renderPackageIcons(path: string): PackageIcons;
18
+ /** The SDK default icon, for projects that set no `icon`. */
19
+ export declare function defaultPackageIcons(): PackageIcons;
20
+ /** The project's icon when it sets one, otherwise the SDK default. */
21
+ export declare function packageIcons(icon: string | undefined): PackageIcons;
22
+ /** What check reports: which icon a build would use, relative to the project. */
23
+ export interface IconReport {
24
+ /** `layout`: a native layout without `icon`, whose metadata owns PACKAGE_ICON*.PNG. */
25
+ source: PackageIcons["source"] | "layout";
26
+ path?: string;
27
+ solid: boolean;
28
+ }
29
+ export declare function iconReport(root: string, icon: string | undefined): IconReport;
30
+ export declare function writeDsmWindowIcons(uiDir: string, icons: PackageIcons): void;
31
+ export declare function writePackageCenterIcons(spkRoot: string, icons: PackageIcons): void;