@synopackageland/cli 0.6.0 → 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.
Files changed (585) hide show
  1. package/CHANGELOG.md +613 -0
  2. package/README.md +81 -78
  3. package/dist/add.js +39 -16
  4. package/dist/authorization-sdk.d.ts +7 -0
  5. package/dist/authorization-sdk.js +7 -0
  6. package/dist/build-spk/delegate-scope.d.ts +6 -0
  7. package/dist/build-spk/delegate-scope.js +34 -0
  8. package/dist/build-spk/dsm-arch.d.ts +7 -1
  9. package/dist/build-spk/dsm-arch.js +24 -28
  10. package/dist/build-spk/dsm-platforms.json +39 -0
  11. package/dist/build-spk/dsm-version.d.ts +11 -0
  12. package/dist/build-spk/dsm-version.js +17 -0
  13. package/dist/build-spk/gateway.d.ts +1 -1
  14. package/dist/build-spk/gateway.js +2 -2
  15. package/dist/build-spk/generator.js +30 -5
  16. package/dist/build-spk/notices.js +4 -1
  17. package/dist/build-spk/resource-worker.js +3 -0
  18. package/dist/build-spk/wizard-messages.d.ts +66 -0
  19. package/dist/build-spk/wizard-messages.js +75 -9
  20. package/dist/cli.js +30 -18
  21. package/dist/contract/schema-validate.js +8 -0
  22. package/dist/contract/validate.js +30 -0
  23. package/dist/deploy/deploy.d.ts +1 -1
  24. package/dist/deploy/deploy.js +8 -0
  25. package/dist/deploy/plan.js +1 -1
  26. package/dist/deploy/spk-version.js +1 -1
  27. package/dist/error-registry.js +46 -13
  28. package/dist/host/dsm-client.d.ts +8 -4
  29. package/dist/host/dsm-client.js +10 -4
  30. package/dist/host/types.d.ts +2 -1
  31. package/dist/info.js +18 -2
  32. package/dist/init.d.ts +3 -0
  33. package/dist/init.js +49 -18
  34. package/dist/package-metadata.d.ts +21 -0
  35. package/dist/package-metadata.js +101 -0
  36. package/dist/portal/alias.d.ts +25 -0
  37. package/dist/portal/alias.js +48 -0
  38. package/dist/portal/package.d.ts +33 -0
  39. package/dist/portal/package.js +116 -0
  40. package/dist/runtime/delegate-contract.d.ts +79 -0
  41. package/dist/runtime/delegate-contract.js +27 -0
  42. package/dist/runtime/executor-build.d.ts +1 -1
  43. package/dist/runtime/executor-build.js +5 -4
  44. package/dist/runtime/executor-inspect.d.ts +3 -0
  45. package/dist/runtime/executor-inspect.js +11 -5
  46. package/dist/runtime/executor-policy.d.ts +12 -0
  47. package/dist/runtime/executor-policy.js +43 -3
  48. package/dist/runtime/executor-scope-task.d.ts +4 -0
  49. package/dist/runtime/executor-scope-task.js +21 -0
  50. package/dist/runtime/executor-tasks.d.ts +2 -1
  51. package/dist/runtime/executor-tasks.js +4 -4
  52. package/dist/skill.js +1 -0
  53. package/dist/standalone/api-permissions.d.ts +10 -0
  54. package/dist/standalone/api-permissions.js +19 -2
  55. package/dist/standalone/background.d.ts +16 -0
  56. package/dist/standalone/background.js +69 -2
  57. package/dist/standalone/binary.d.ts +1 -1
  58. package/dist/standalone/binary.js +22 -8
  59. package/dist/standalone/build.d.ts +1 -1
  60. package/dist/standalone/build.js +38 -8
  61. package/dist/standalone/daemon.d.ts +1 -1
  62. package/dist/standalone/daemon.js +2 -1
  63. package/dist/standalone/dsm-window.d.ts +3 -1
  64. package/dist/standalone/dsm-window.js +72 -15
  65. package/dist/standalone/inspect-spk.d.ts +9 -1
  66. package/dist/standalone/inspect-spk.js +119 -26
  67. package/dist/standalone/lifecycle.js +86 -8
  68. package/dist/standalone/manifest.d.ts +13 -0
  69. package/dist/standalone/manifest.js +57 -8
  70. package/dist/standalone/native-authorization-window.d.ts +2 -0
  71. package/dist/standalone/native-authorization-window.js +30 -0
  72. package/dist/standalone/native-layout.d.ts +82 -0
  73. package/dist/standalone/native-layout.js +377 -0
  74. package/dist/standalone/native-root-window.d.ts +26 -0
  75. package/dist/standalone/native-root-window.js +282 -0
  76. package/dist/standalone/portal-window.d.ts +21 -0
  77. package/dist/standalone/portal-window.js +155 -0
  78. package/dist/standalone/portal.d.ts +4 -0
  79. package/dist/standalone/portal.js +4 -0
  80. package/dist/standalone/resource.d.ts +5 -3
  81. package/dist/standalone/resource.js +6 -3
  82. package/dist/standalone/root-window.js +62 -15
  83. package/dist/standalone/spk.d.ts +1 -1
  84. package/dist/standalone/spk.js +25 -7
  85. package/dist/templates/_daemon/main_test.go +61 -8
  86. package/dist/templates/_executor/README.md +127 -16
  87. package/dist/templates/_executor/anchor.go +146 -0
  88. package/dist/templates/_executor/anchor_test.go +126 -0
  89. package/dist/templates/_executor/apppriv_review_test.go +1 -1
  90. package/dist/templates/_executor/cancel_contract_test.go +236 -0
  91. package/dist/templates/_executor/copy.go +64 -0
  92. package/dist/templates/_executor/copy_test.go +88 -0
  93. package/dist/templates/_executor/dsm.go +23 -10
  94. package/dist/templates/_executor/dsm_test.go +95 -1
  95. package/dist/templates/_executor/executor.go +260 -49
  96. package/dist/templates/_executor/executor_test.go +36 -6
  97. package/dist/templates/_executor/identity.go +27 -1
  98. package/dist/templates/_executor/identity_kernel_linux_test.go +60 -0
  99. package/dist/templates/_executor/identity_linux.go +82 -0
  100. package/dist/templates/_executor/identity_security_test.go +43 -0
  101. package/dist/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
  102. package/dist/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
  103. package/dist/templates/_executor/internal/taskscript/boot.sh +9 -9
  104. package/dist/templates/_executor/internal/taskscript/cmd/main.go +2 -2
  105. package/dist/templates/_executor/internal/taskscript/control.sh +15 -10
  106. package/dist/templates/_executor/internal/taskscript/tasks.go +5 -3
  107. package/dist/templates/_executor/lifecycle_test.go +11 -0
  108. package/dist/templates/_executor/link_linux.go +28 -0
  109. package/dist/templates/_executor/long_running_test.go +530 -0
  110. package/dist/templates/_executor/main.go +72 -20
  111. package/dist/templates/_executor/move_linux.go +490 -0
  112. package/dist/templates/_executor/move_linux_test.go +460 -0
  113. package/dist/templates/_executor/move_validation.go +46 -0
  114. package/dist/templates/_executor/move_validation_test.go +187 -0
  115. package/dist/templates/_executor/operations.go +926 -0
  116. package/dist/templates/_executor/platform_linux.go +24 -173
  117. package/dist/templates/_executor/platform_linux_test.go +9 -65
  118. package/dist/templates/_executor/platform_other.go +30 -4
  119. package/dist/templates/_executor/process.go +3 -0
  120. package/dist/templates/_executor/records.go +242 -0
  121. package/dist/templates/_executor/scope_cancel_contract_test.go +91 -0
  122. package/dist/templates/_executor/scope_client.go +37 -0
  123. package/dist/templates/_executor/scope_contract.go +12 -0
  124. package/dist/templates/_executor/selected_scope.go +146 -0
  125. package/dist/templates/_executor/selected_scope_test.go +186 -0
  126. package/dist/templates/_executor/status_disabled_test.go +33 -0
  127. package/dist/templates/_executor/store.go +4 -3
  128. package/dist/templates/_executor/supervise.go +109 -0
  129. package/dist/templates/_executor/supervise_test.go +130 -0
  130. package/dist/templates/_executor/task_race_review_test.go +1 -1
  131. package/dist/templates/_executor/tasks.go +7 -8
  132. package/dist/templates/_executor/tasks_review_test.go +1 -1
  133. package/dist/templates/_executor/tasks_test.go +4 -4
  134. package/dist/templates/_executor/watch.go +8 -0
  135. package/dist/templates/_executor/watch_test.go +23 -2
  136. package/dist/templates/_executor/write_review_linux_test.go +4 -12
  137. package/dist/templates/_shared/AGENTS.md +129 -0
  138. package/dist/templates/binary/dsm-package.yaml +24 -0
  139. package/dist/templates/binary/i18n/messages/de.json +4 -0
  140. package/dist/templates/binary/i18n/messages/en.json +4 -0
  141. package/dist/templates/binary/i18n/messages/es.json +4 -0
  142. package/dist/templates/binary/i18n/messages/fr.json +4 -0
  143. package/dist/templates/binary/i18n/messages/it.json +4 -0
  144. package/dist/templates/binary/i18n/messages/ja.json +4 -0
  145. package/dist/templates/binary/i18n/messages/ko.json +4 -0
  146. package/dist/templates/binary/i18n/messages/zh-CN.json +4 -0
  147. package/dist/templates/binary/i18n/messages/zh-TW.json +4 -0
  148. package/dist/templates/binary/ui/app.js +19 -4
  149. package/dist/templates/native-authorization/AuthorizationGate.vue +91 -0
  150. package/dist/templates/native-authorization/i18n/de.json +37 -0
  151. package/dist/templates/native-authorization/i18n/en.json +37 -0
  152. package/dist/templates/native-authorization/i18n/es.json +37 -0
  153. package/dist/templates/native-authorization/i18n/fr.json +37 -0
  154. package/dist/templates/native-authorization/i18n/index.ts +15 -0
  155. package/dist/templates/native-authorization/i18n/it.json +37 -0
  156. package/dist/templates/native-authorization/i18n/ja.json +37 -0
  157. package/dist/templates/native-authorization/i18n/ko.json +37 -0
  158. package/dist/templates/native-authorization/i18n/zh-CN.json +37 -0
  159. package/dist/templates/native-authorization/i18n/zh-TW.json +37 -0
  160. package/dist/templates/native-go/README.md +43 -10
  161. package/dist/templates/native-go/backend/cmd/app/main.go +27 -7
  162. package/dist/templates/native-go/backend/internal/api/entry_test.go +47 -0
  163. package/dist/templates/native-go/backend/internal/api/permissions_test.go +3 -3
  164. package/dist/templates/native-go/backend/internal/api/registry.go +11 -0
  165. package/dist/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
  166. package/dist/templates/native-go/backend/internal/api/server.go +18 -5
  167. package/dist/templates/native-go/backend/internal/app/delegate_config.go +57 -0
  168. package/dist/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
  169. package/dist/templates/native-go/backend/internal/app/portal.go +30 -0
  170. package/dist/templates/native-go/backend/internal/app/portal_test.go +55 -0
  171. package/dist/templates/native-go/backend/internal/app/routes.go +8 -2
  172. package/dist/templates/native-go/backend/internal/background/runner.go +1 -1
  173. package/dist/templates/native-go/backend/internal/background/store.go +16 -14
  174. package/dist/templates/native-go/backend/internal/dsm/admin.go +8 -2
  175. package/dist/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
  176. package/dist/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
  177. package/dist/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
  178. package/dist/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
  179. package/dist/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
  180. package/dist/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
  181. package/dist/templates/native-go/backend/internal/dsm/entry.go +177 -0
  182. package/dist/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
  183. package/dist/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
  184. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
  185. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
  186. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
  187. package/dist/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
  188. package/dist/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
  189. package/dist/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
  190. package/dist/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
  191. package/dist/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
  192. package/dist/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
  193. package/dist/templates/native-go/backend/internal/filestation/service.go +1 -1
  194. package/dist/templates/native-go/backend/internal/portal/portal.go +138 -0
  195. package/dist/templates/native-go/backend/internal/portal/portal_test.go +89 -0
  196. package/dist/templates/native-go/dsm-package.yaml +20 -1
  197. package/dist/templates/native-go/i18n/glossary.json +2 -1
  198. package/dist/templates/native-go/i18n/messages/de.json +1 -0
  199. package/dist/templates/native-go/i18n/messages/en.json +1 -0
  200. package/dist/templates/native-go/i18n/messages/es.json +1 -0
  201. package/dist/templates/native-go/i18n/messages/fr.json +1 -0
  202. package/dist/templates/native-go/i18n/messages/it.json +1 -0
  203. package/dist/templates/native-go/i18n/messages/ja.json +1 -0
  204. package/dist/templates/native-go/i18n/messages/ko.json +1 -0
  205. package/dist/templates/native-go/i18n/messages/zh-CN.json +1 -0
  206. package/dist/templates/native-go/i18n/messages/zh-TW.json +1 -0
  207. package/dist/templates/native-go/ui/app.css +10 -0
  208. package/dist/templates/native-go/ui/app.js +11 -1
  209. package/dist/templates/native-go-delegate/DELEGATE.md +126 -5
  210. package/dist/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
  211. package/dist/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
  212. package/dist/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
  213. package/dist/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
  214. package/dist/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
  215. package/dist/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
  216. package/dist/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
  217. package/dist/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
  218. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
  219. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
  220. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
  221. package/dist/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
  222. package/dist/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
  223. package/dist/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
  224. package/dist/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
  225. package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
  226. package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
  227. package/dist/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
  228. package/dist/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
  229. package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
  230. package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
  231. package/dist/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
  232. package/dist/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
  233. package/dist/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
  234. package/dist/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
  235. package/dist/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
  236. package/dist/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
  237. package/dist/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
  238. package/dist/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
  239. package/dist/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
  240. package/dist/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
  241. package/dist/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
  242. package/dist/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
  243. package/dist/templates/native-go-delegate/test.sh +1 -0
  244. package/dist/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
  245. package/dist/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
  246. package/dist/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
  247. package/dist/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
  248. package/dist/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
  249. package/dist/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
  250. package/dist/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
  251. package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
  252. package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
  253. package/dist/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
  254. package/dist/templates/native-go-vue/README.md +4 -0
  255. package/dist/templates/native-go-vue/frontend/package-lock.json +4 -4
  256. package/dist/templates/native-go-vue/frontend/package.json +1 -1
  257. package/dist/templates/native-go-vue/frontend/src/App.vue +18 -13
  258. package/dist/templates/native-go-vue/frontend/src/context.ts +31 -0
  259. package/dist/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +52 -8
  260. package/dist/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
  261. package/dist/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
  262. package/dist/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
  263. package/dist/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +4 -2
  264. package/dist/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
  265. package/dist/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
  266. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/de.json +46 -0
  267. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/en.json +12 -2
  268. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/es.json +46 -0
  269. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +46 -0
  270. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/it.json +46 -0
  271. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +46 -0
  272. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +46 -0
  273. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
  274. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
  275. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
  276. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
  277. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
  278. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
  279. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
  280. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
  281. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
  282. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +46 -0
  283. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +15 -5
  284. package/dist/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
  285. package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
  286. package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
  287. package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
  288. package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
  289. package/dist/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
  290. package/dist/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
  291. package/dist/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
  292. package/dist/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
  293. package/dist/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
  294. package/dist/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
  295. package/dist/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
  296. package/dist/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
  297. package/dist/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
  298. package/dist/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
  299. package/dist/templates/native-go-vue/frontend/src/i18n.ts +13 -0
  300. package/dist/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
  301. package/dist/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
  302. package/dist/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
  303. package/dist/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
  304. package/dist/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
  305. package/dist/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
  306. package/dist/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
  307. package/dist/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
  308. package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
  309. package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
  310. package/dist/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
  311. package/dist/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
  312. package/dist/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
  313. package/dist/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
  314. package/dist/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
  315. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
  316. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
  317. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
  318. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
  319. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
  320. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
  321. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
  322. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
  323. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
  324. package/dist/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
  325. package/dist/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
  326. package/dist/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
  327. package/dist/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
  328. package/dist/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
  329. package/dist/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
  330. package/dist/validate.js +2 -1
  331. package/package.json +12 -2
  332. package/schema/package-metadata.schema.json +101 -0
  333. package/schema/synology-app.schema.json +112 -0
  334. package/skills/SKILL.md +109 -3
  335. package/skills/reference/create.md +101 -2
  336. package/skills/reference/deploy.md +2 -2
  337. package/skills/reference/files.md +113 -2
  338. package/skills/reference/identity.md +70 -1
  339. package/skills/reference/portal.md +17 -0
  340. package/skills/reference/ui-vue.md +12 -0
  341. package/templates/_daemon/main_test.go +61 -8
  342. package/templates/_executor/README.md +127 -16
  343. package/templates/_executor/anchor.go +146 -0
  344. package/templates/_executor/anchor_test.go +126 -0
  345. package/templates/_executor/apppriv_review_test.go +1 -1
  346. package/templates/_executor/cancel_contract_test.go +236 -0
  347. package/templates/_executor/copy.go +64 -0
  348. package/templates/_executor/copy_test.go +88 -0
  349. package/templates/_executor/dsm.go +23 -10
  350. package/templates/_executor/dsm_test.go +95 -1
  351. package/templates/_executor/executor.go +260 -49
  352. package/templates/_executor/executor_test.go +36 -6
  353. package/templates/_executor/identity.go +27 -1
  354. package/templates/_executor/identity_kernel_linux_test.go +60 -0
  355. package/templates/_executor/identity_linux.go +82 -0
  356. package/templates/_executor/identity_security_test.go +43 -0
  357. package/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
  358. package/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
  359. package/templates/_executor/internal/taskscript/boot.sh +9 -9
  360. package/templates/_executor/internal/taskscript/cmd/main.go +2 -2
  361. package/templates/_executor/internal/taskscript/control.sh +15 -10
  362. package/templates/_executor/internal/taskscript/tasks.go +5 -3
  363. package/templates/_executor/lifecycle_test.go +11 -0
  364. package/templates/_executor/link_linux.go +28 -0
  365. package/templates/_executor/long_running_test.go +530 -0
  366. package/templates/_executor/main.go +72 -20
  367. package/templates/_executor/move_linux.go +490 -0
  368. package/templates/_executor/move_linux_test.go +460 -0
  369. package/templates/_executor/move_validation.go +46 -0
  370. package/templates/_executor/move_validation_test.go +187 -0
  371. package/templates/_executor/operations.go +926 -0
  372. package/templates/_executor/platform_linux.go +24 -173
  373. package/templates/_executor/platform_linux_test.go +9 -65
  374. package/templates/_executor/platform_other.go +30 -4
  375. package/templates/_executor/process.go +3 -0
  376. package/templates/_executor/records.go +242 -0
  377. package/templates/_executor/scope_cancel_contract_test.go +91 -0
  378. package/templates/_executor/scope_client.go +37 -0
  379. package/templates/_executor/scope_contract.go +12 -0
  380. package/templates/_executor/selected_scope.go +146 -0
  381. package/templates/_executor/selected_scope_test.go +186 -0
  382. package/templates/_executor/status_disabled_test.go +33 -0
  383. package/templates/_executor/store.go +4 -3
  384. package/templates/_executor/supervise.go +109 -0
  385. package/templates/_executor/supervise_test.go +130 -0
  386. package/templates/_executor/task_race_review_test.go +1 -1
  387. package/templates/_executor/tasks.go +7 -8
  388. package/templates/_executor/tasks_review_test.go +1 -1
  389. package/templates/_executor/tasks_test.go +4 -4
  390. package/templates/_executor/watch.go +8 -0
  391. package/templates/_executor/watch_test.go +23 -2
  392. package/templates/_executor/write_review_linux_test.go +4 -12
  393. package/templates/_shared/AGENTS.md +129 -0
  394. package/templates/binary/dsm-package.yaml +24 -0
  395. package/templates/binary/i18n/messages/de.json +4 -0
  396. package/templates/binary/i18n/messages/en.json +4 -0
  397. package/templates/binary/i18n/messages/es.json +4 -0
  398. package/templates/binary/i18n/messages/fr.json +4 -0
  399. package/templates/binary/i18n/messages/it.json +4 -0
  400. package/templates/binary/i18n/messages/ja.json +4 -0
  401. package/templates/binary/i18n/messages/ko.json +4 -0
  402. package/templates/binary/i18n/messages/zh-CN.json +4 -0
  403. package/templates/binary/i18n/messages/zh-TW.json +4 -0
  404. package/templates/binary/ui/app.js +19 -4
  405. package/templates/native-authorization/AuthorizationGate.vue +91 -0
  406. package/templates/native-authorization/i18n/de.json +37 -0
  407. package/templates/native-authorization/i18n/en.json +37 -0
  408. package/templates/native-authorization/i18n/es.json +37 -0
  409. package/templates/native-authorization/i18n/fr.json +37 -0
  410. package/templates/native-authorization/i18n/index.ts +15 -0
  411. package/templates/native-authorization/i18n/it.json +37 -0
  412. package/templates/native-authorization/i18n/ja.json +37 -0
  413. package/templates/native-authorization/i18n/ko.json +37 -0
  414. package/templates/native-authorization/i18n/zh-CN.json +37 -0
  415. package/templates/native-authorization/i18n/zh-TW.json +37 -0
  416. package/templates/native-go/README.md +43 -10
  417. package/templates/native-go/backend/cmd/app/main.go +27 -7
  418. package/templates/native-go/backend/internal/api/entry_test.go +47 -0
  419. package/templates/native-go/backend/internal/api/permissions_test.go +3 -3
  420. package/templates/native-go/backend/internal/api/registry.go +11 -0
  421. package/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
  422. package/templates/native-go/backend/internal/api/server.go +18 -5
  423. package/templates/native-go/backend/internal/app/delegate_config.go +57 -0
  424. package/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
  425. package/templates/native-go/backend/internal/app/portal.go +30 -0
  426. package/templates/native-go/backend/internal/app/portal_test.go +55 -0
  427. package/templates/native-go/backend/internal/app/routes.go +8 -2
  428. package/templates/native-go/backend/internal/background/runner.go +1 -1
  429. package/templates/native-go/backend/internal/background/store.go +16 -14
  430. package/templates/native-go/backend/internal/dsm/admin.go +8 -2
  431. package/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
  432. package/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
  433. package/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
  434. package/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
  435. package/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
  436. package/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
  437. package/templates/native-go/backend/internal/dsm/entry.go +177 -0
  438. package/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
  439. package/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
  440. package/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
  441. package/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
  442. package/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
  443. package/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
  444. package/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
  445. package/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
  446. package/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
  447. package/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
  448. package/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
  449. package/templates/native-go/backend/internal/filestation/service.go +1 -1
  450. package/templates/native-go/backend/internal/portal/portal.go +138 -0
  451. package/templates/native-go/backend/internal/portal/portal_test.go +89 -0
  452. package/templates/native-go/dsm-package.yaml +20 -1
  453. package/templates/native-go/i18n/glossary.json +2 -1
  454. package/templates/native-go/i18n/messages/de.json +1 -0
  455. package/templates/native-go/i18n/messages/en.json +1 -0
  456. package/templates/native-go/i18n/messages/es.json +1 -0
  457. package/templates/native-go/i18n/messages/fr.json +1 -0
  458. package/templates/native-go/i18n/messages/it.json +1 -0
  459. package/templates/native-go/i18n/messages/ja.json +1 -0
  460. package/templates/native-go/i18n/messages/ko.json +1 -0
  461. package/templates/native-go/i18n/messages/zh-CN.json +1 -0
  462. package/templates/native-go/i18n/messages/zh-TW.json +1 -0
  463. package/templates/native-go/ui/app.css +10 -0
  464. package/templates/native-go/ui/app.js +11 -1
  465. package/templates/native-go-delegate/DELEGATE.md +126 -5
  466. package/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
  467. package/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
  468. package/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
  469. package/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
  470. package/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
  471. package/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
  472. package/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
  473. package/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
  474. package/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
  475. package/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
  476. package/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
  477. package/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
  478. package/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
  479. package/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
  480. package/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
  481. package/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
  482. package/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
  483. package/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
  484. package/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
  485. package/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
  486. package/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
  487. package/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
  488. package/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
  489. package/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
  490. package/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
  491. package/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
  492. package/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
  493. package/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
  494. package/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
  495. package/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
  496. package/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
  497. package/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
  498. package/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
  499. package/templates/native-go-delegate/test.sh +1 -0
  500. package/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
  501. package/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
  502. package/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
  503. package/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
  504. package/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
  505. package/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
  506. package/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
  507. package/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
  508. package/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
  509. package/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
  510. package/templates/native-go-vue/README.md +4 -0
  511. package/templates/native-go-vue/frontend/package-lock.json +4 -4
  512. package/templates/native-go-vue/frontend/package.json +1 -1
  513. package/templates/native-go-vue/frontend/src/App.vue +18 -13
  514. package/templates/native-go-vue/frontend/src/context.ts +31 -0
  515. package/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +52 -8
  516. package/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
  517. package/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
  518. package/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
  519. package/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +4 -2
  520. package/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
  521. package/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
  522. package/templates/native-go-vue/frontend/src/delegate/i18n/de.json +46 -0
  523. package/templates/native-go-vue/frontend/src/delegate/i18n/en.json +12 -2
  524. package/templates/native-go-vue/frontend/src/delegate/i18n/es.json +46 -0
  525. package/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +46 -0
  526. package/templates/native-go-vue/frontend/src/delegate/i18n/it.json +46 -0
  527. package/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +46 -0
  528. package/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +46 -0
  529. package/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
  530. package/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
  531. package/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
  532. package/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
  533. package/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
  534. package/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
  535. package/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
  536. package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
  537. package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
  538. package/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +46 -0
  539. package/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +15 -5
  540. package/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
  541. package/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
  542. package/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
  543. package/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
  544. package/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
  545. package/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
  546. package/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
  547. package/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
  548. package/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
  549. package/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
  550. package/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
  551. package/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
  552. package/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
  553. package/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
  554. package/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
  555. package/templates/native-go-vue/frontend/src/i18n.ts +13 -0
  556. package/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
  557. package/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
  558. package/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
  559. package/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
  560. package/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
  561. package/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
  562. package/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
  563. package/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
  564. package/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
  565. package/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
  566. package/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
  567. package/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
  568. package/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
  569. package/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
  570. package/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
  571. package/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
  572. package/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
  573. package/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
  574. package/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
  575. package/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
  576. package/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
  577. package/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
  578. package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
  579. package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
  580. package/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
  581. package/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
  582. package/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
  583. package/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
  584. package/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
  585. package/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
@@ -41,3 +41,17 @@ test('failed status loading offers a retry and releases the mounting class',asyn
41
41
  f.app.unmount();expect(f.root.classList.contains('dsmapp-vue-root')).toBe(false)
42
42
  }finally{f.close()}
43
43
  })
44
+ test('a portal app shows the Application Portal section on the status page',async()=>{
45
+ const without=fixture('Plain')
46
+ const f=fixture('Portal')
47
+ try{
48
+ await settle();expect(without.root.textContent).not.toContain('Application Portal')
49
+ f.app.unmount()
50
+ const status={state:'active',alias:'portal',url:'https://nas.example/portal/',canManage:false,controlPanel:false,defaultAlias:'portal'} as const
51
+ f.ctx.portal={messages:{title:'Application Portal',link:'Direct link:'},status:vi.fn(async()=>status),apply:vi.fn(),disable:vi.fn(),openControlPanel:vi.fn(),mountPanel:vi.fn()}
52
+ const app=mount(f.root,f.ctx);await settle()
53
+ expect(f.root.textContent).toContain('Application Portal')
54
+ expect(f.root.querySelector('a[href="https://nas.example/portal/"]')).not.toBeNull()
55
+ app.unmount()
56
+ }finally{without.close();f.root.remove()}
57
+ })
@@ -0,0 +1,71 @@
1
+ // @vitest-environment jsdom
2
+ import {expect,test,vi} from 'vitest'
3
+ import {createApp,h,nextTick} from 'vue'
4
+ import {AppRoot} from '@synopackageland/ui'
5
+ import PortalSettings from '../src/portal/PortalSettings.vue'
6
+ import type {PortalAccess,PortalStatus} from '../src/context'
7
+
8
+ const messages={title:'Application Portal',link:'Direct link:',inactive:'Not active.',askAdmin:'Ask an administrator',alias:'Alias',apply:'Apply',disable:'Turn off',advanced:'Advanced',controlPanel:'Open Control Panel',portal_alias_in_use:'Alias in use',portal_unavailable:'DSM refused'}
9
+ const base:PortalStatus={state:'inactive',canManage:false,controlPanel:false,defaultAlias:'my-app'}
10
+ function access(status:PortalStatus,overrides:Partial<PortalAccess>={}):PortalAccess{
11
+ return {messages,status:vi.fn(async()=>status),apply:vi.fn(async()=>status),disable:vi.fn(async()=>status),openControlPanel:vi.fn(),mountPanel:vi.fn(),...overrides}
12
+ }
13
+ async function mount(portal:PortalAccess){
14
+ const root=document.createElement('div');document.body.append(root)
15
+ const app=createApp({render:()=>h(AppRoot,{},()=>h(PortalSettings,{portal}))})
16
+ app.mount(root);await nextTick();await nextTick();await new Promise(r=>setTimeout(r));await nextTick()
17
+ return {root,unmount(){app.unmount();root.remove()}}
18
+ }
19
+ const buttons=(root:HTMLElement)=>[...root.querySelectorAll('button')].map(b=>b.textContent?.trim())
20
+
21
+ test('an ordinary user sees the active link and nothing to change',async()=>{
22
+ const {root,unmount}=await mount(access({...base,state:'active',alias:'my-app',url:'https://nas.example/my-app/'}))
23
+ try{
24
+ expect(root.querySelector('a')?.getAttribute('href')).toBe('https://nas.example/my-app/')
25
+ expect(root.querySelector('input')).toBeNull();expect(root.querySelector('button')).toBeNull()
26
+ }finally{unmount()}
27
+ })
28
+
29
+ test('an ordinary user without an active alias is asked to contact an administrator',async()=>{
30
+ const {root,unmount}=await mount(access({...base,state:'unavailable'}))
31
+ try{
32
+ expect(root.textContent).toContain('Ask an administrator')
33
+ expect(root.querySelector('a,input,button')).toBeNull()
34
+ }finally{unmount()}
35
+ })
36
+
37
+ test('an administrator applies the prefilled alias and sees DSM refusals as portal text',async()=>{
38
+ const apply=vi.fn(async()=>Promise.reject({code:'portal_alias_in_use'}))
39
+ const portal=access({...base,canManage:true},{apply})
40
+ const {root,unmount}=await mount(portal)
41
+ try{
42
+ const input=root.querySelector('input')!
43
+ expect(input.value).toBe('my-app')
44
+ root.querySelector('form')!.dispatchEvent(new Event('submit',{cancelable:true}))
45
+ await new Promise(r=>setTimeout(r));await nextTick()
46
+ expect(apply).toHaveBeenCalledWith('my-app')
47
+ expect(root.querySelector('[role="alert"]')?.textContent).toContain('Alias in use')
48
+ ;[...root.querySelectorAll('button')].find(b=>b.textContent?.includes('Advanced'))!.click()
49
+ expect(portal.openControlPanel).toHaveBeenCalled()
50
+ }finally{unmount()}
51
+ })
52
+
53
+ test('an administrator turns an active alias off',async()=>{
54
+ const portal=access({...base,state:'active',alias:'my-app',url:'https://nas.example/my-app/',canManage:true})
55
+ const {root,unmount}=await mount(portal)
56
+ try{
57
+ expect(root.querySelector('a')?.getAttribute('href')).toBe('https://nas.example/my-app/')
58
+ ;[...root.querySelectorAll('button')].find(b=>b.textContent?.includes('Turn off'))!.click()
59
+ await nextTick()
60
+ expect(portal.disable).toHaveBeenCalled()
61
+ }finally{unmount()}
62
+ })
63
+
64
+ test('an administrator without DSM portal support gets only the Control Panel shortcut',async()=>{
65
+ const portal=access({...base,state:'unavailable',controlPanel:true})
66
+ const {root,unmount}=await mount(portal)
67
+ try{
68
+ expect(root.querySelector('input')).toBeNull()
69
+ expect(buttons(root)).toEqual(['Open Control Panel'])
70
+ }finally{unmount()}
71
+ })
@@ -0,0 +1,50 @@
1
+ // @vitest-environment jsdom
2
+ // @vitest-environment-options {"url":"https://nas.test"}
3
+ import {expect,test,vi} from 'vitest'
4
+ import {nextTick} from 'vue'
5
+ import {mount} from '../src/main'
6
+ import type {Context} from '../src/context'
7
+ import {appCopy} from '../src/i18n'
8
+ import {identityCopy} from '../src/identity/i18n'
9
+ async function settle(){for(let i=0;i<20;i++){await Promise.resolve();await nextTick()}}
10
+ const buttons=(root:HTMLElement)=>[...root.querySelectorAll('button')].map(b=>b.textContent?.trim())
11
+ function start(locale:string,call:(method:string)=>Promise<unknown>){
12
+ const ctx={locale,call:vi.fn(call),reopen(){return ()=>{}}} as unknown as Context
13
+ const root=document.createElement('div');document.body.append(root)
14
+ const app=mount(root,ctx)
15
+ return {root,close(){app.unmount();root.remove()}}
16
+ }
17
+ test('the status page and its errors follow the DSM language',async()=>{
18
+ const copy=appCopy('ger')
19
+ const {root,close}=start('de',async method=>{
20
+ if(method==='app.status')return {package:'Pkg',version:'1',user:'admin',admin:true}
21
+ if(method==='greeting.get')throw {code:'admin_required'}
22
+ throw {code:'unknown_method'}
23
+ })
24
+ try{
25
+ await settle()
26
+ expect(buttons(root)).toContain(copy.refresh)
27
+ expect(root.textContent).toContain(copy.statusTitle)
28
+ expect(root.textContent).toContain(copy.greeting)
29
+ expect(root.textContent).toContain(copy.errors.admin_required)
30
+ expect(root.querySelector('[aria-label]')?.getAttribute('aria-label')).not.toBe('Package settings')
31
+ }finally{close()}
32
+ })
33
+ test('unknown failures name the code in the DSM language',()=>{
34
+ expect(appCopy('ja').errors.request_failed).toContain('{code}')
35
+ })
36
+ test('the sign-in page and its session notices follow the DSM language',async()=>{
37
+ const copy=identityCopy('jpn')
38
+ const {root,close}=start('ja',async method=>{
39
+ if(method==='identity.status')return {enabled:true}
40
+ if(method==='identity.session')return {user:'alice',uid:'1',expiresAt:new Date(Date.now()-1000).toISOString()}
41
+ throw {code:'session_required'}
42
+ })
43
+ try{
44
+ await settle()
45
+ expect(root.textContent).toContain(copy.title)
46
+ expect(buttons(root)).toEqual(expect.arrayContaining([copy.signIn,copy.continueDSM]))
47
+ expect(root.querySelector('[role="status"]')?.textContent).toBe(copy.notices.expired)
48
+ expect(root.textContent).not.toMatch(/Sign in|Account|Password|session/)
49
+ }finally{close()}
50
+ })
package/dist/validate.js CHANGED
@@ -6,6 +6,7 @@ import { validateContract } from "./contract/validate.js";
6
6
  import { findListingUnsupportedInstallTypes } from "./contract/unsupported-types.js";
7
7
  import { classifyComposeRoute, collectComposeInterpolations, collectVolumeSourceInterpolations, loadCompose, validateAdminPortMapping, validateComposeHostBinds, validateComposeNumericCommandArgs, validateComposeRunAs, validateComposeSecurity, validateGatewayPortLoopback, } from "./compose/analyze.js";
8
8
  import { usesAuthGateway } from "./contract/web-launch.js";
9
+ import { isNativeLayout, loadNativeLayout } from "./standalone/native-layout.js";
9
10
  import { loadStandaloneManifest } from "./standalone/manifest.js";
10
11
  import { COMPOSE_FILENAME, CONTRACT_FILENAME, DSM_PACKAGE_FILENAME, } from "./discovery.js";
11
12
  import { declaredPrivilegeFlags } from "./compose/privilege.js";
@@ -26,7 +27,7 @@ export function validateProject(project, options = {}) {
26
27
  }] };
27
28
  }
28
29
  if (hasStandalone) {
29
- const loaded = loadStandaloneManifest(project.root);
30
+ const loaded = isNativeLayout(project.root) ? loadNativeLayout(project.root) : loadStandaloneManifest(project.root);
30
31
  return loaded.ok ? { ok: true, errors: [] } : { ok: false, errors: loaded.errors.map(error => ({
31
32
  ...error, span: { file: DSM_PACKAGE_FILENAME, line: 1, column: 1 },
32
33
  suggestion: "請修正 dsm-package.yaml 的 schema 2 欄位與能力宣告。",
package/package.json CHANGED
@@ -1,13 +1,17 @@
1
1
  {
2
2
  "name": "@synopackageland/cli",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Syno Package Land Developer Kit CLI",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "synopkgland": "./dist/bin.js"
8
8
  },
9
+ "engines": {
10
+ "node": ">=22.12"
11
+ },
9
12
  "files": [
10
13
  "dist",
14
+ "CHANGELOG.md",
11
15
  "templates",
12
16
  "schema",
13
17
  "skills"
@@ -32,5 +36,11 @@
32
36
  "access": "public",
33
37
  "registry": "https://registry.npmjs.org"
34
38
  },
35
- "license": "MIT"
39
+ "license": "MIT",
40
+ "exports": {
41
+ "./authorization-sdk": "./dist/authorization-sdk.js",
42
+ "./dist/*": "./dist/*",
43
+ "./package.json": "./package.json",
44
+ "./native-layout": "./dist/standalone/native-layout.js"
45
+ }
36
46
  }
@@ -0,0 +1,101 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type": "object",
4
+ "additionalProperties": false,
5
+ "properties": {
6
+ "changelog": {
7
+ "oneOf": [
8
+ {
9
+ "type": "string",
10
+ "maxLength": 16000
11
+ },
12
+ {
13
+ "type": "object",
14
+ "maxProperties": 32,
15
+ "additionalProperties": {
16
+ "type": "string",
17
+ "maxLength": 16000
18
+ }
19
+ }
20
+ ]
21
+ },
22
+ "contact_email": {
23
+ "type": "string",
24
+ "maxLength": 16000,
25
+ "pattern": "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$"
26
+ },
27
+ "support_email": {
28
+ "type": "string",
29
+ "maxLength": 16000,
30
+ "pattern": "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$"
31
+ },
32
+ "homepage": {
33
+ "type": "string",
34
+ "maxLength": 16000,
35
+ "pattern": "^https?://"
36
+ },
37
+ "source_url": {
38
+ "type": "string",
39
+ "maxLength": 16000,
40
+ "pattern": "^https?://"
41
+ },
42
+ "issues_url": {
43
+ "type": "string",
44
+ "maxLength": 16000,
45
+ "pattern": "^https?://"
46
+ },
47
+ "license": {
48
+ "type": "string",
49
+ "maxLength": 16000
50
+ },
51
+ "maintainer_url": {
52
+ "type": "string",
53
+ "maxLength": 16000,
54
+ "pattern": "^https?://"
55
+ },
56
+ "distributor": {
57
+ "type": "string",
58
+ "maxLength": 16000
59
+ },
60
+ "distributor_url": {
61
+ "type": "string",
62
+ "maxLength": 16000,
63
+ "pattern": "^https?://"
64
+ },
65
+ "support_url": {
66
+ "type": "string",
67
+ "maxLength": 16000,
68
+ "pattern": "^(https?://|mailto:)"
69
+ },
70
+ "helpurl": {
71
+ "type": "string",
72
+ "maxLength": 16000,
73
+ "pattern": "^https?://"
74
+ },
75
+ "long_description": {
76
+ "oneOf": [
77
+ {
78
+ "type": "string",
79
+ "maxLength": 16000
80
+ },
81
+ {
82
+ "type": "object",
83
+ "maxProperties": 32,
84
+ "additionalProperties": {
85
+ "type": "string",
86
+ "maxLength": 16000
87
+ }
88
+ }
89
+ ]
90
+ },
91
+ "screenshots": {
92
+ "type": "array",
93
+ "maxItems": 12,
94
+ "items": {
95
+ "type": "string",
96
+ "pattern": "^https?://",
97
+ "maxLength": 2048
98
+ }
99
+ }
100
+ }
101
+ }
@@ -118,6 +118,18 @@
118
118
  "pattern": "^(?:[A-Za-z0-9._-]{1,64}|[A-Za-z0-9._-]{1,64}\\\\[A-Za-z0-9._-](?:[A-Za-z0-9._ -]{0,126}[A-Za-z0-9._-])?|[A-Za-z0-9._-](?:[A-Za-z0-9._ -]{0,126}[A-Za-z0-9._-])?@[A-Za-z0-9._-]{1,64})$(?![\\s\\S])"
119
119
  },
120
120
  "description": "DSM group names allowed in; only with access: dsm-groups."
121
+ },
122
+ "portal": {
123
+ "type": "object",
124
+ "properties": {
125
+ "alias": {
126
+ "type": "string",
127
+ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$",
128
+ "description": "Default DSM Application Portal alias (https://<nas>/<alias>/). Omit to use the package name. An administrator still applies it."
129
+ }
130
+ },
131
+ "additionalProperties": false,
132
+ "description": "Register the App in DSM Control Panel > Login Portal > Applications. Needs launch: dsm-window behind the DSM gateway (access other than public) and os_min_ver 7.3.2-86009 or later. Registration alone exposes nothing."
121
133
  }
122
134
  },
123
135
  "additionalProperties": true
@@ -149,6 +161,106 @@
149
161
  "type": "boolean"
150
162
  }
151
163
  }
164
+ },
165
+ "metadata": {
166
+ "type": "object",
167
+ "additionalProperties": false,
168
+ "properties": {
169
+ "changelog": {
170
+ "oneOf": [
171
+ {
172
+ "type": "string",
173
+ "maxLength": 16000
174
+ },
175
+ {
176
+ "type": "object",
177
+ "maxProperties": 32,
178
+ "additionalProperties": {
179
+ "type": "string",
180
+ "maxLength": 16000
181
+ }
182
+ }
183
+ ]
184
+ },
185
+ "contact_email": {
186
+ "type": "string",
187
+ "maxLength": 16000,
188
+ "pattern": "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$"
189
+ },
190
+ "support_email": {
191
+ "type": "string",
192
+ "maxLength": 16000,
193
+ "pattern": "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$"
194
+ },
195
+ "homepage": {
196
+ "type": "string",
197
+ "maxLength": 16000,
198
+ "pattern": "^https?://"
199
+ },
200
+ "source_url": {
201
+ "type": "string",
202
+ "maxLength": 16000,
203
+ "pattern": "^https?://"
204
+ },
205
+ "issues_url": {
206
+ "type": "string",
207
+ "maxLength": 16000,
208
+ "pattern": "^https?://"
209
+ },
210
+ "license": {
211
+ "type": "string",
212
+ "maxLength": 16000
213
+ },
214
+ "maintainer_url": {
215
+ "type": "string",
216
+ "maxLength": 16000,
217
+ "pattern": "^https?://"
218
+ },
219
+ "distributor": {
220
+ "type": "string",
221
+ "maxLength": 16000
222
+ },
223
+ "distributor_url": {
224
+ "type": "string",
225
+ "maxLength": 16000,
226
+ "pattern": "^https?://"
227
+ },
228
+ "support_url": {
229
+ "type": "string",
230
+ "maxLength": 16000,
231
+ "pattern": "^(https?://|mailto:)"
232
+ },
233
+ "helpurl": {
234
+ "type": "string",
235
+ "maxLength": 16000,
236
+ "pattern": "^https?://"
237
+ },
238
+ "long_description": {
239
+ "oneOf": [
240
+ {
241
+ "type": "string",
242
+ "maxLength": 16000
243
+ },
244
+ {
245
+ "type": "object",
246
+ "maxProperties": 32,
247
+ "additionalProperties": {
248
+ "type": "string",
249
+ "maxLength": 16000
250
+ }
251
+ }
252
+ ]
253
+ },
254
+ "screenshots": {
255
+ "type": "array",
256
+ "maxItems": 12,
257
+ "items": {
258
+ "type": "string",
259
+ "pattern": "^https?://",
260
+ "maxLength": 2048
261
+ }
262
+ }
263
+ }
152
264
  }
153
265
  },
154
266
  "additionalProperties": true
package/skills/SKILL.md CHANGED
@@ -5,15 +5,15 @@ description: Initialize, extend, check, build, inspect, and deploy Synology appl
5
5
 
6
6
  # Independent Synology SPKs
7
7
 
8
- Use this guide to initialize, build and inspect own applications or upstream OSS as independent packages. 依已實作能力區分 DSM session 檔案、私有 jobs 與 App 登入;delegate 為 P2 整合中,禁止發明已完成的離線委託或新身分平台。
8
+ Use this guide to initialize, build and inspect own applications or upstream OSS as independent packages. 依已實作能力區分 DSM session 檔案、私有 jobs 與 App 登入;delegate 已實作並隨 CLI 提供固定操作的離線委託(預設 `files.moveFromStaging`);共用 delegate/rootOps executor 的完整裝置生命週期驗收仍待完成,不得宣稱已通過;支援邊界依 delegate guide/support matrix,禁止發明新的身分平台。
9
9
 
10
10
  Start with `synopkgland init -t native-go`, `synopkgland init -t binary`, or `synopkgland init -t compose`. Read reference/create.md or reference/wrap.md, then reference/deploy.md. Native CGI session checks belong to the package. Container authentication belongs to upstream; fixed service credentials govern mounted data access.
11
11
 
12
12
  Never install, uninstall, publish or modify NAS data without task authorization. Prefer check, inspect and deploy --dry-run for reviewable artifacts.
13
13
 
14
- Native projects use schema 2 capabilities and `--with files,jobs,login,root-ops`; use `add` for existing projects. Prefer `check --json`, `build --json`, `inspect <spk> --json`, `deploy --dry-run --json`, and `status --host <profile> --json` for structured results. Read the conflict policy in reference/create.md before adding overlays.
14
+ Native projects use schema 2 capabilities and `--with files,jobs,login,root-ops,delegate`; use `add` for existing projects. Prefer `check --json`, `build --json`, `inspect <spk> --json`, `deploy --dry-run --json`, and `status --host <profile> --json` for structured results. Read the conflict policy in reference/create.md before adding overlays.
15
15
 
16
- Read reference/files.md and reference/identity.md for capability boundaries. RootOps currently uses individual administrator task approval; P2 will share one-time protected executor setup with delegate. App sessions alone do not grant NAS file authority.
16
+ Read reference/portal.md before declaring or changing a DSM Application Portal alias (`add portal`); DSM owns the saved setting. Read reference/files.md and reference/identity.md for capability boundaries. RootOps and delegate share one-time protected executor boot/control setup with digest approval. Existing native products can explicitly use the separate authorization-sdk build-time adapter; do not mix its tasks with generated executor capabilities. App sessions alone do not grant NAS file authority.
17
17
 
18
18
  Read [reference/ui-vue.md](reference/ui-vue.md) when editing Vue components in the native-go Vue template; use the installed SDK contracts, keep DSM embedding boundaries, and verify the actual app.
19
19
 
@@ -23,3 +23,109 @@ For UI discovery, run `npx --no syno-pkg-land-ui catalog --json` and
23
23
  `npx --no syno-pkg-land-ui describe Button --json` from the installed frontend.
24
24
  Read its prompt and exported Vue docs/types before choosing component APIs.
25
25
  Use `syno-pkg-land-ui` directly in npm scripts; keep AI guidance version-independent.
26
+
27
+ For existing native products, schema 2 `backend: {kind: native}` preserves project-owned payload/metadata, prepare/compile argv hooks and pinned toolkits. See the native-layout guide; run `check`, `build`, then `inspect <spk>` locally. Keep lifecycle/systemd as the package account and preserve product-owned digest approval/revocation. Native layouts do not opt into generated Go capabilities.
28
+
29
+
30
+ ## Permanent destination integration
31
+
32
+ `init --with delegate` / `add delegate` default to `operations: [files.moveFromStaging]`,
33
+ `destinations: [save]`, `lifetime: until-revoked`, `scope: install-selected`. Existing legacy
34
+ TTL declarations retain their 1–3600 second service / 30-day wire ceiling and
35
+ 64 MiB / 60-second URL example. Do not apply those limits to the new move API.
36
+ Delegate can coexist with daemon; ordinary standalone jobs cannot. Preserve
37
+ App business route floors. Binary/compose remain unsupported.
38
+
39
+ Use File Station `/home[/...]`, never `/homes/<user>`. The SDK destination picker
40
+ selection itself grants access after fresh DSM session/UID/write verification,
41
+ without a second consent dialog. Ordinary and administrator subjects use their
42
+ own nonzero UID/current groups, never root. An online App can create an in-scope
43
+ grant using a valid session; there is no trusted external consent or notification.
44
+
45
+ Use the default `createBackgroundSaveFacade(ctx)` / CapabilityPanels management
46
+ page. `delegate.status` exposes verified `disabled` and manifest mode; missing
47
+ protected evidence must not imply enabled. `delegate.operations.list` accepts
48
+ only `{}`, uses the backend move mirrors, and returns the caller's username+UID
49
+ operations only, including for admins. Mirrors are not completion receipts:
50
+ query original `delegate.operations.get` and show Saved only for committed with
51
+ a receipt. Cancel by the same reference; revoke by grant ID. Never resubmit
52
+ uncertain/interrupted work. Admin disable is protected and revokes grants;
53
+ enable/mailbox start does not resurrect them. Keep IDs, never session credentials.
54
+
55
+ App-owned daemon completion and scheduled CSV export call configured Go
56
+ `Service.MoveFromStaging` with `delegation_id`, stable `job_id`, private relative
57
+ `staging`, `name`, `size`. No owner/UID selector. Bounds: 16 GiB/file, queued16,
58
+ active1/package, 24-hour attempt, 5-second revalidation ticks (one check at a time, 30-second complete-check deadline; proven timeouts retain private copying, publication still revalidates), 10 MiB operation records,
59
+ 50 MiB audit. Scope is a usage restriction, not hard subtree confinement.
60
+ Local production-executor fixtures use fake DSM/peer/bulk writer; do not claim
61
+ NAS ACL, actual writer UID, logout/reboot or full lifecycle acceptance from them.
62
+ Gopeed product wiring remains a separate task.
63
+
64
+ Admission recovery (per job): on `EXECUTOR_UNAVAILABLE`, `EXECUTOR_TIMEOUT`,
65
+ `EXECUTOR_PROTOCOL`, `canceled`, `EXECUTOR_PAUSED`, `queue-full`,
66
+ `STORAGE_ERROR`, `ADMISSION_PENDING`, `jobs_busy` or `jobs_unavailable` (the
67
+ package journal was busy or failed transiently; a caller deadline or cancel
68
+ spent waiting for it is `canceled`), call `MoveFromStaging` again later with
69
+ the same exact params. It queries the original reference first and re-sends
70
+ admission only when the executor does not know it and the pinned source is
71
+ unchanged; executor tuple deduplication keeps one operation, so a lost reply or a
72
+ racing caller never copies twice. At most 10 possibly-delivered sends, 2 s
73
+ backoff doubling to 5 min; the worker sweep does the same. Terminal, do not
74
+ retry: `APP_DENIED`, `DELEGATION_DENIED`, `operation-conflict`, `disabled`,
75
+ `SCOPE_DENIED` and other executor refusals, `STAGING_CHANGED`,
76
+ `ADMISSION_EXHAUSTED`, `spool_unsafe` and `journal_corrupt` (repair the package
77
+ spool first), and `operation-not-found` for an accepted operation.
78
+ Never change job/grant IDs, delete mirrors or call the socket directly to retry.
79
+
80
+ Cancellation (per job): `CancelOperation` / `delegate.operations.cancel` with the
81
+ original ref is idempotent; repeat it with the same ref after any retryable
82
+ error or a lost reply. A reply `queued`→`canceled` is final at once. A copy in
83
+ flight answers `copying` with code `CANCEL_REQUESTED`: the cancel is accepted and
84
+ durable, not finished; poll `OperationStatus` on the same ref until terminal
85
+ (repeating the cancel is harmless). `canceled` (`OPERATION_CANCELED`) guarantees the writer
86
+ stopped, its part file is removed, nothing was published and staging is kept; it
87
+ stays canceled across executor crash, package stop/start and logout. Revoke, scope change and disable store their reason (`grant-revoked`,
88
+ `scope-changed`, `integration-disabled`) the same way: a copy in flight answers
89
+ `CANCEL_REQUESTED` with it and settles `canceled` with it across a restart. A
90
+ copy the executor stops without a cancel ends `interrupted`/`EXECUTOR_PAUSED`
91
+ (`interrupted`/`interrupted` after a crash), never `WRITE_FAILED`. `committed`
92
+ means publication won the race: the file stays (cancel never removes it) and only
93
+ the app record may be dropped. `uncertain` means a publish attempt failed before
94
+ the cancel; keep querying. A cancel of a ref the executor has not admitted yet
95
+ (reserved/sent mirror) returns `canceled` and leaves a tombstone, so a late or
96
+ recovered admission of that ref returns `canceled` and never copies; a producer
97
+ cancel is also written to the mirror first, so `MoveFromStaging` and the worker
98
+ sweep forward the cancel instead of admitting it.
99
+
100
+
101
+ ### Install-selected scope and the destination API
102
+
103
+ - The DSM install wizard dynamically lists local shares (`SYNO.Core.Share list`
104
+ via `api_store`) and offers home. It saves only a package-owned pre-selection
105
+ in `var/delegate-install.json`; never trust that file for authority.
106
+ - The existing administrator PasswordConfirm form displays this pre-selection
107
+ at first enable. `ctx.executor.authorize(password, selectedScope)` confirms it
108
+ through a pinned, exact-readback one-time root task. Settings changes use the
109
+ same form/password path; no App CGI route may set protected scope directly.
110
+ - The executor trusts `/usr/local/etc/synopkgland/<pkg>/delegations/selected-scope.record`
111
+ only. Its scope/generation are runtime protected state; shipped policy pins
112
+ lock the selection mode and operations. Changes revoke old grants and cancel
113
+ pending writes. Change-away-and-back never revives an old grant.
114
+ - Follow `selection` from verified `delegate.status` / `sdk.destination(key)`.
115
+ If the draft differs, display the difference and follow the protected value.
116
+ Home and fixed `shared:<name>` manifests stay compatible.
117
+ - Frontend: `const sdk = createBackgroundSaveFacade(ctx); const current = await
118
+ sdk.destination('save')` returns typed `{key, selection, destination, status}`.
119
+ `selection` contains `{scope, root, generation}`; `destination` is this caller's
120
+ grant or null. Handle active/missing/reselection-required/needs-scope-confirmation/disabled.
121
+ - Go: `Service.Destination(ctx, caller, request, key)` verifies the fresh DSM
122
+ session and username+UID. Capture its active grant ID into the App job. The
123
+ offline producer uses existing `Service.MoveFromStaging`; no user/UID selector,
124
+ cookie, token, or browser path cache. Executor revalidates at use/publication.
125
+ - The generated Background saves page includes a working **Save example file**
126
+ (`sdk.exportExample({key, job_id})`, `delegate.example.export`). Go
127
+ `ExportExample` creates a private JSON file, calls `MoveFromStaging` once, and
128
+ repeats the original request on repeated IDs. Review `example.go` to
129
+ adapt a real producer; show Saved only from a protected committed receipt.
130
+ - Wizard support is measured on vt-nas DSM 7.4 via a session-only SSH local
131
+ forward. This is not proof of other DSM releases or full writer/reboot behavior.