@synopackageland/cli 0.6.1 → 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 (578) hide show
  1. package/CHANGELOG.md +613 -0
  2. package/README.md +81 -89
  3. package/dist/add.js +39 -16
  4. package/dist/build-spk/delegate-scope.d.ts +6 -0
  5. package/dist/build-spk/delegate-scope.js +34 -0
  6. package/dist/build-spk/dsm-arch.d.ts +7 -1
  7. package/dist/build-spk/dsm-arch.js +24 -28
  8. package/dist/build-spk/dsm-platforms.json +39 -0
  9. package/dist/build-spk/dsm-version.d.ts +11 -0
  10. package/dist/build-spk/dsm-version.js +17 -0
  11. package/dist/build-spk/gateway.d.ts +1 -1
  12. package/dist/build-spk/gateway.js +2 -2
  13. package/dist/build-spk/generator.js +30 -5
  14. package/dist/build-spk/notices.js +4 -1
  15. package/dist/build-spk/resource-worker.js +3 -0
  16. package/dist/build-spk/wizard-messages.d.ts +66 -0
  17. package/dist/build-spk/wizard-messages.js +75 -9
  18. package/dist/cli.js +15 -7
  19. package/dist/contract/schema-validate.js +8 -0
  20. package/dist/contract/validate.js +30 -0
  21. package/dist/deploy/deploy.d.ts +1 -1
  22. package/dist/deploy/deploy.js +8 -0
  23. package/dist/deploy/plan.js +1 -1
  24. package/dist/deploy/spk-version.js +1 -1
  25. package/dist/error-registry.js +43 -15
  26. package/dist/host/dsm-client.d.ts +8 -4
  27. package/dist/host/dsm-client.js +10 -4
  28. package/dist/host/types.d.ts +2 -1
  29. package/dist/info.js +18 -2
  30. package/dist/init.d.ts +3 -0
  31. package/dist/init.js +49 -18
  32. package/dist/package-metadata.d.ts +21 -0
  33. package/dist/package-metadata.js +101 -0
  34. package/dist/portal/alias.d.ts +25 -0
  35. package/dist/portal/alias.js +48 -0
  36. package/dist/portal/package.d.ts +33 -0
  37. package/dist/portal/package.js +116 -0
  38. package/dist/runtime/delegate-contract.d.ts +79 -0
  39. package/dist/runtime/delegate-contract.js +27 -0
  40. package/dist/runtime/executor-build.d.ts +1 -1
  41. package/dist/runtime/executor-build.js +5 -4
  42. package/dist/runtime/executor-inspect.d.ts +3 -0
  43. package/dist/runtime/executor-inspect.js +11 -5
  44. package/dist/runtime/executor-policy.d.ts +12 -0
  45. package/dist/runtime/executor-policy.js +43 -3
  46. package/dist/runtime/executor-scope-task.d.ts +4 -0
  47. package/dist/runtime/executor-scope-task.js +21 -0
  48. package/dist/runtime/executor-tasks.d.ts +2 -1
  49. package/dist/runtime/executor-tasks.js +4 -4
  50. package/dist/skill.js +1 -0
  51. package/dist/standalone/api-permissions.d.ts +10 -0
  52. package/dist/standalone/api-permissions.js +19 -2
  53. package/dist/standalone/background.d.ts +16 -0
  54. package/dist/standalone/background.js +69 -2
  55. package/dist/standalone/binary.d.ts +1 -1
  56. package/dist/standalone/binary.js +22 -8
  57. package/dist/standalone/build.d.ts +1 -1
  58. package/dist/standalone/build.js +38 -8
  59. package/dist/standalone/daemon.d.ts +1 -1
  60. package/dist/standalone/daemon.js +2 -1
  61. package/dist/standalone/dsm-window.d.ts +3 -1
  62. package/dist/standalone/dsm-window.js +72 -15
  63. package/dist/standalone/inspect-spk.d.ts +8 -0
  64. package/dist/standalone/inspect-spk.js +105 -26
  65. package/dist/standalone/lifecycle.js +86 -8
  66. package/dist/standalone/manifest.d.ts +13 -0
  67. package/dist/standalone/manifest.js +57 -8
  68. package/dist/standalone/native-authorization-window.d.ts +1 -1
  69. package/dist/standalone/native-authorization-window.js +2 -0
  70. package/dist/standalone/native-layout.d.ts +3 -0
  71. package/dist/standalone/native-layout.js +37 -5
  72. package/dist/standalone/portal-window.d.ts +21 -0
  73. package/dist/standalone/portal-window.js +155 -0
  74. package/dist/standalone/portal.d.ts +4 -0
  75. package/dist/standalone/portal.js +4 -0
  76. package/dist/standalone/resource.d.ts +5 -3
  77. package/dist/standalone/resource.js +6 -3
  78. package/dist/standalone/root-window.js +62 -15
  79. package/dist/standalone/spk.d.ts +1 -1
  80. package/dist/standalone/spk.js +25 -7
  81. package/dist/templates/_daemon/main_test.go +61 -8
  82. package/dist/templates/_executor/README.md +127 -16
  83. package/dist/templates/_executor/anchor.go +146 -0
  84. package/dist/templates/_executor/anchor_test.go +126 -0
  85. package/dist/templates/_executor/apppriv_review_test.go +1 -1
  86. package/dist/templates/_executor/cancel_contract_test.go +236 -0
  87. package/dist/templates/_executor/copy.go +64 -0
  88. package/dist/templates/_executor/copy_test.go +88 -0
  89. package/dist/templates/_executor/dsm.go +23 -10
  90. package/dist/templates/_executor/dsm_test.go +95 -1
  91. package/dist/templates/_executor/executor.go +260 -49
  92. package/dist/templates/_executor/executor_test.go +36 -6
  93. package/dist/templates/_executor/identity.go +27 -1
  94. package/dist/templates/_executor/identity_kernel_linux_test.go +60 -0
  95. package/dist/templates/_executor/identity_linux.go +82 -0
  96. package/dist/templates/_executor/identity_security_test.go +43 -0
  97. package/dist/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
  98. package/dist/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
  99. package/dist/templates/_executor/internal/taskscript/boot.sh +9 -9
  100. package/dist/templates/_executor/internal/taskscript/cmd/main.go +2 -2
  101. package/dist/templates/_executor/internal/taskscript/control.sh +15 -10
  102. package/dist/templates/_executor/internal/taskscript/tasks.go +5 -3
  103. package/dist/templates/_executor/lifecycle_test.go +11 -0
  104. package/dist/templates/_executor/link_linux.go +28 -0
  105. package/dist/templates/_executor/long_running_test.go +530 -0
  106. package/dist/templates/_executor/main.go +72 -20
  107. package/dist/templates/_executor/move_linux.go +490 -0
  108. package/dist/templates/_executor/move_linux_test.go +460 -0
  109. package/dist/templates/_executor/move_validation.go +46 -0
  110. package/dist/templates/_executor/move_validation_test.go +187 -0
  111. package/dist/templates/_executor/operations.go +926 -0
  112. package/dist/templates/_executor/platform_linux.go +24 -173
  113. package/dist/templates/_executor/platform_linux_test.go +9 -65
  114. package/dist/templates/_executor/platform_other.go +30 -4
  115. package/dist/templates/_executor/process.go +3 -0
  116. package/dist/templates/_executor/records.go +242 -0
  117. package/dist/templates/_executor/scope_cancel_contract_test.go +91 -0
  118. package/dist/templates/_executor/scope_client.go +37 -0
  119. package/dist/templates/_executor/scope_contract.go +12 -0
  120. package/dist/templates/_executor/selected_scope.go +146 -0
  121. package/dist/templates/_executor/selected_scope_test.go +186 -0
  122. package/dist/templates/_executor/status_disabled_test.go +33 -0
  123. package/dist/templates/_executor/store.go +4 -3
  124. package/dist/templates/_executor/supervise.go +109 -0
  125. package/dist/templates/_executor/supervise_test.go +130 -0
  126. package/dist/templates/_executor/task_race_review_test.go +1 -1
  127. package/dist/templates/_executor/tasks.go +7 -8
  128. package/dist/templates/_executor/tasks_review_test.go +1 -1
  129. package/dist/templates/_executor/tasks_test.go +4 -4
  130. package/dist/templates/_executor/watch.go +8 -0
  131. package/dist/templates/_executor/watch_test.go +23 -2
  132. package/dist/templates/_executor/write_review_linux_test.go +4 -12
  133. package/dist/templates/_shared/AGENTS.md +129 -0
  134. package/dist/templates/binary/dsm-package.yaml +24 -0
  135. package/dist/templates/binary/i18n/messages/de.json +4 -0
  136. package/dist/templates/binary/i18n/messages/en.json +4 -0
  137. package/dist/templates/binary/i18n/messages/es.json +4 -0
  138. package/dist/templates/binary/i18n/messages/fr.json +4 -0
  139. package/dist/templates/binary/i18n/messages/it.json +4 -0
  140. package/dist/templates/binary/i18n/messages/ja.json +4 -0
  141. package/dist/templates/binary/i18n/messages/ko.json +4 -0
  142. package/dist/templates/binary/i18n/messages/zh-CN.json +4 -0
  143. package/dist/templates/binary/i18n/messages/zh-TW.json +4 -0
  144. package/dist/templates/binary/ui/app.js +19 -4
  145. package/dist/templates/native-authorization/AuthorizationGate.vue +5 -3
  146. package/dist/templates/native-authorization/i18n/de.json +1 -0
  147. package/dist/templates/native-authorization/i18n/en.json +1 -0
  148. package/dist/templates/native-authorization/i18n/es.json +2 -1
  149. package/dist/templates/native-authorization/i18n/fr.json +1 -0
  150. package/dist/templates/native-authorization/i18n/it.json +11 -10
  151. package/dist/templates/native-authorization/i18n/ja.json +1 -0
  152. package/dist/templates/native-authorization/i18n/ko.json +10 -9
  153. package/dist/templates/native-authorization/i18n/zh-CN.json +6 -5
  154. package/dist/templates/native-authorization/i18n/zh-TW.json +6 -5
  155. package/dist/templates/native-go/README.md +43 -10
  156. package/dist/templates/native-go/backend/cmd/app/main.go +27 -7
  157. package/dist/templates/native-go/backend/internal/api/entry_test.go +47 -0
  158. package/dist/templates/native-go/backend/internal/api/permissions_test.go +3 -3
  159. package/dist/templates/native-go/backend/internal/api/registry.go +11 -0
  160. package/dist/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
  161. package/dist/templates/native-go/backend/internal/api/server.go +18 -5
  162. package/dist/templates/native-go/backend/internal/app/delegate_config.go +57 -0
  163. package/dist/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
  164. package/dist/templates/native-go/backend/internal/app/portal.go +30 -0
  165. package/dist/templates/native-go/backend/internal/app/portal_test.go +55 -0
  166. package/dist/templates/native-go/backend/internal/app/routes.go +8 -2
  167. package/dist/templates/native-go/backend/internal/background/runner.go +1 -1
  168. package/dist/templates/native-go/backend/internal/background/store.go +16 -14
  169. package/dist/templates/native-go/backend/internal/dsm/admin.go +8 -2
  170. package/dist/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
  171. package/dist/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
  172. package/dist/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
  173. package/dist/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
  174. package/dist/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
  175. package/dist/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
  176. package/dist/templates/native-go/backend/internal/dsm/entry.go +177 -0
  177. package/dist/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
  178. package/dist/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
  179. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
  180. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
  181. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
  182. package/dist/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
  183. package/dist/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
  184. package/dist/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
  185. package/dist/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
  186. package/dist/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
  187. package/dist/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
  188. package/dist/templates/native-go/backend/internal/filestation/service.go +1 -1
  189. package/dist/templates/native-go/backend/internal/portal/portal.go +138 -0
  190. package/dist/templates/native-go/backend/internal/portal/portal_test.go +89 -0
  191. package/dist/templates/native-go/dsm-package.yaml +20 -1
  192. package/dist/templates/native-go/i18n/glossary.json +2 -1
  193. package/dist/templates/native-go/i18n/messages/de.json +1 -0
  194. package/dist/templates/native-go/i18n/messages/en.json +1 -0
  195. package/dist/templates/native-go/i18n/messages/es.json +1 -0
  196. package/dist/templates/native-go/i18n/messages/fr.json +1 -0
  197. package/dist/templates/native-go/i18n/messages/it.json +1 -0
  198. package/dist/templates/native-go/i18n/messages/ja.json +1 -0
  199. package/dist/templates/native-go/i18n/messages/ko.json +1 -0
  200. package/dist/templates/native-go/i18n/messages/zh-CN.json +1 -0
  201. package/dist/templates/native-go/i18n/messages/zh-TW.json +1 -0
  202. package/dist/templates/native-go/ui/app.css +10 -0
  203. package/dist/templates/native-go/ui/app.js +11 -1
  204. package/dist/templates/native-go-delegate/DELEGATE.md +126 -5
  205. package/dist/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
  206. package/dist/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
  207. package/dist/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
  208. package/dist/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
  209. package/dist/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
  210. package/dist/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
  211. package/dist/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
  212. package/dist/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
  213. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
  214. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
  215. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
  216. package/dist/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
  217. package/dist/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
  218. package/dist/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
  219. package/dist/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
  220. package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
  221. package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
  222. package/dist/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
  223. package/dist/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
  224. package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
  225. package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
  226. package/dist/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
  227. package/dist/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
  228. package/dist/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
  229. package/dist/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
  230. package/dist/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
  231. package/dist/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
  232. package/dist/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
  233. package/dist/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
  234. package/dist/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
  235. package/dist/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
  236. package/dist/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
  237. package/dist/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
  238. package/dist/templates/native-go-delegate/test.sh +1 -0
  239. package/dist/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
  240. package/dist/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
  241. package/dist/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
  242. package/dist/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
  243. package/dist/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
  244. package/dist/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
  245. package/dist/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
  246. package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
  247. package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
  248. package/dist/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
  249. package/dist/templates/native-go-vue/README.md +4 -0
  250. package/dist/templates/native-go-vue/frontend/package-lock.json +4 -4
  251. package/dist/templates/native-go-vue/frontend/package.json +1 -1
  252. package/dist/templates/native-go-vue/frontend/src/App.vue +18 -13
  253. package/dist/templates/native-go-vue/frontend/src/context.ts +31 -0
  254. package/dist/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +52 -8
  255. package/dist/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
  256. package/dist/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
  257. package/dist/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
  258. package/dist/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +4 -2
  259. package/dist/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
  260. package/dist/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
  261. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/de.json +46 -0
  262. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/en.json +12 -2
  263. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/es.json +46 -0
  264. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +46 -0
  265. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/it.json +46 -0
  266. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +46 -0
  267. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +46 -0
  268. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
  269. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
  270. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
  271. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
  272. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
  273. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
  274. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
  275. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
  276. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
  277. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +46 -0
  278. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +15 -5
  279. package/dist/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
  280. package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
  281. package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
  282. package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
  283. package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
  284. package/dist/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
  285. package/dist/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
  286. package/dist/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
  287. package/dist/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
  288. package/dist/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
  289. package/dist/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
  290. package/dist/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
  291. package/dist/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
  292. package/dist/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
  293. package/dist/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
  294. package/dist/templates/native-go-vue/frontend/src/i18n.ts +13 -0
  295. package/dist/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
  296. package/dist/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
  297. package/dist/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
  298. package/dist/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
  299. package/dist/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
  300. package/dist/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
  301. package/dist/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
  302. package/dist/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
  303. package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
  304. package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
  305. package/dist/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
  306. package/dist/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
  307. package/dist/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
  308. package/dist/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
  309. package/dist/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
  310. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
  311. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
  312. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
  313. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
  314. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
  315. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
  316. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
  317. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
  318. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
  319. package/dist/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
  320. package/dist/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
  321. package/dist/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
  322. package/dist/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
  323. package/dist/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
  324. package/dist/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
  325. package/package.json +5 -1
  326. package/schema/package-metadata.schema.json +101 -0
  327. package/schema/synology-app.schema.json +112 -0
  328. package/skills/SKILL.md +106 -4
  329. package/skills/reference/create.md +101 -2
  330. package/skills/reference/deploy.md +2 -2
  331. package/skills/reference/files.md +113 -2
  332. package/skills/reference/identity.md +70 -1
  333. package/skills/reference/portal.md +17 -0
  334. package/skills/reference/ui-vue.md +12 -0
  335. package/templates/_daemon/main_test.go +61 -8
  336. package/templates/_executor/README.md +127 -16
  337. package/templates/_executor/anchor.go +146 -0
  338. package/templates/_executor/anchor_test.go +126 -0
  339. package/templates/_executor/apppriv_review_test.go +1 -1
  340. package/templates/_executor/cancel_contract_test.go +236 -0
  341. package/templates/_executor/copy.go +64 -0
  342. package/templates/_executor/copy_test.go +88 -0
  343. package/templates/_executor/dsm.go +23 -10
  344. package/templates/_executor/dsm_test.go +95 -1
  345. package/templates/_executor/executor.go +260 -49
  346. package/templates/_executor/executor_test.go +36 -6
  347. package/templates/_executor/identity.go +27 -1
  348. package/templates/_executor/identity_kernel_linux_test.go +60 -0
  349. package/templates/_executor/identity_linux.go +82 -0
  350. package/templates/_executor/identity_security_test.go +43 -0
  351. package/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
  352. package/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
  353. package/templates/_executor/internal/taskscript/boot.sh +9 -9
  354. package/templates/_executor/internal/taskscript/cmd/main.go +2 -2
  355. package/templates/_executor/internal/taskscript/control.sh +15 -10
  356. package/templates/_executor/internal/taskscript/tasks.go +5 -3
  357. package/templates/_executor/lifecycle_test.go +11 -0
  358. package/templates/_executor/link_linux.go +28 -0
  359. package/templates/_executor/long_running_test.go +530 -0
  360. package/templates/_executor/main.go +72 -20
  361. package/templates/_executor/move_linux.go +490 -0
  362. package/templates/_executor/move_linux_test.go +460 -0
  363. package/templates/_executor/move_validation.go +46 -0
  364. package/templates/_executor/move_validation_test.go +187 -0
  365. package/templates/_executor/operations.go +926 -0
  366. package/templates/_executor/platform_linux.go +24 -173
  367. package/templates/_executor/platform_linux_test.go +9 -65
  368. package/templates/_executor/platform_other.go +30 -4
  369. package/templates/_executor/process.go +3 -0
  370. package/templates/_executor/records.go +242 -0
  371. package/templates/_executor/scope_cancel_contract_test.go +91 -0
  372. package/templates/_executor/scope_client.go +37 -0
  373. package/templates/_executor/scope_contract.go +12 -0
  374. package/templates/_executor/selected_scope.go +146 -0
  375. package/templates/_executor/selected_scope_test.go +186 -0
  376. package/templates/_executor/status_disabled_test.go +33 -0
  377. package/templates/_executor/store.go +4 -3
  378. package/templates/_executor/supervise.go +109 -0
  379. package/templates/_executor/supervise_test.go +130 -0
  380. package/templates/_executor/task_race_review_test.go +1 -1
  381. package/templates/_executor/tasks.go +7 -8
  382. package/templates/_executor/tasks_review_test.go +1 -1
  383. package/templates/_executor/tasks_test.go +4 -4
  384. package/templates/_executor/watch.go +8 -0
  385. package/templates/_executor/watch_test.go +23 -2
  386. package/templates/_executor/write_review_linux_test.go +4 -12
  387. package/templates/_shared/AGENTS.md +129 -0
  388. package/templates/binary/dsm-package.yaml +24 -0
  389. package/templates/binary/i18n/messages/de.json +4 -0
  390. package/templates/binary/i18n/messages/en.json +4 -0
  391. package/templates/binary/i18n/messages/es.json +4 -0
  392. package/templates/binary/i18n/messages/fr.json +4 -0
  393. package/templates/binary/i18n/messages/it.json +4 -0
  394. package/templates/binary/i18n/messages/ja.json +4 -0
  395. package/templates/binary/i18n/messages/ko.json +4 -0
  396. package/templates/binary/i18n/messages/zh-CN.json +4 -0
  397. package/templates/binary/i18n/messages/zh-TW.json +4 -0
  398. package/templates/binary/ui/app.js +19 -4
  399. package/templates/native-authorization/AuthorizationGate.vue +5 -3
  400. package/templates/native-authorization/i18n/de.json +1 -0
  401. package/templates/native-authorization/i18n/en.json +1 -0
  402. package/templates/native-authorization/i18n/es.json +2 -1
  403. package/templates/native-authorization/i18n/fr.json +1 -0
  404. package/templates/native-authorization/i18n/it.json +11 -10
  405. package/templates/native-authorization/i18n/ja.json +1 -0
  406. package/templates/native-authorization/i18n/ko.json +10 -9
  407. package/templates/native-authorization/i18n/zh-CN.json +6 -5
  408. package/templates/native-authorization/i18n/zh-TW.json +6 -5
  409. package/templates/native-go/README.md +43 -10
  410. package/templates/native-go/backend/cmd/app/main.go +27 -7
  411. package/templates/native-go/backend/internal/api/entry_test.go +47 -0
  412. package/templates/native-go/backend/internal/api/permissions_test.go +3 -3
  413. package/templates/native-go/backend/internal/api/registry.go +11 -0
  414. package/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
  415. package/templates/native-go/backend/internal/api/server.go +18 -5
  416. package/templates/native-go/backend/internal/app/delegate_config.go +57 -0
  417. package/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
  418. package/templates/native-go/backend/internal/app/portal.go +30 -0
  419. package/templates/native-go/backend/internal/app/portal_test.go +55 -0
  420. package/templates/native-go/backend/internal/app/routes.go +8 -2
  421. package/templates/native-go/backend/internal/background/runner.go +1 -1
  422. package/templates/native-go/backend/internal/background/store.go +16 -14
  423. package/templates/native-go/backend/internal/dsm/admin.go +8 -2
  424. package/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
  425. package/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
  426. package/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
  427. package/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
  428. package/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
  429. package/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
  430. package/templates/native-go/backend/internal/dsm/entry.go +177 -0
  431. package/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
  432. package/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
  433. package/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
  434. package/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
  435. package/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
  436. package/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
  437. package/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
  438. package/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
  439. package/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
  440. package/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
  441. package/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
  442. package/templates/native-go/backend/internal/filestation/service.go +1 -1
  443. package/templates/native-go/backend/internal/portal/portal.go +138 -0
  444. package/templates/native-go/backend/internal/portal/portal_test.go +89 -0
  445. package/templates/native-go/dsm-package.yaml +20 -1
  446. package/templates/native-go/i18n/glossary.json +2 -1
  447. package/templates/native-go/i18n/messages/de.json +1 -0
  448. package/templates/native-go/i18n/messages/en.json +1 -0
  449. package/templates/native-go/i18n/messages/es.json +1 -0
  450. package/templates/native-go/i18n/messages/fr.json +1 -0
  451. package/templates/native-go/i18n/messages/it.json +1 -0
  452. package/templates/native-go/i18n/messages/ja.json +1 -0
  453. package/templates/native-go/i18n/messages/ko.json +1 -0
  454. package/templates/native-go/i18n/messages/zh-CN.json +1 -0
  455. package/templates/native-go/i18n/messages/zh-TW.json +1 -0
  456. package/templates/native-go/ui/app.css +10 -0
  457. package/templates/native-go/ui/app.js +11 -1
  458. package/templates/native-go-delegate/DELEGATE.md +126 -5
  459. package/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
  460. package/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
  461. package/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
  462. package/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
  463. package/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
  464. package/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
  465. package/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
  466. package/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
  467. package/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
  468. package/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
  469. package/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
  470. package/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
  471. package/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
  472. package/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
  473. package/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
  474. package/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
  475. package/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
  476. package/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
  477. package/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
  478. package/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
  479. package/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
  480. package/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
  481. package/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
  482. package/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
  483. package/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
  484. package/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
  485. package/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
  486. package/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
  487. package/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
  488. package/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
  489. package/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
  490. package/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
  491. package/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
  492. package/templates/native-go-delegate/test.sh +1 -0
  493. package/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
  494. package/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
  495. package/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
  496. package/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
  497. package/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
  498. package/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
  499. package/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
  500. package/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
  501. package/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
  502. package/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
  503. package/templates/native-go-vue/README.md +4 -0
  504. package/templates/native-go-vue/frontend/package-lock.json +4 -4
  505. package/templates/native-go-vue/frontend/package.json +1 -1
  506. package/templates/native-go-vue/frontend/src/App.vue +18 -13
  507. package/templates/native-go-vue/frontend/src/context.ts +31 -0
  508. package/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +52 -8
  509. package/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
  510. package/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
  511. package/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
  512. package/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +4 -2
  513. package/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
  514. package/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
  515. package/templates/native-go-vue/frontend/src/delegate/i18n/de.json +46 -0
  516. package/templates/native-go-vue/frontend/src/delegate/i18n/en.json +12 -2
  517. package/templates/native-go-vue/frontend/src/delegate/i18n/es.json +46 -0
  518. package/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +46 -0
  519. package/templates/native-go-vue/frontend/src/delegate/i18n/it.json +46 -0
  520. package/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +46 -0
  521. package/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +46 -0
  522. package/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
  523. package/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
  524. package/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
  525. package/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
  526. package/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
  527. package/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
  528. package/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
  529. package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
  530. package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
  531. package/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +46 -0
  532. package/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +15 -5
  533. package/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
  534. package/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
  535. package/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
  536. package/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
  537. package/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
  538. package/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
  539. package/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
  540. package/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
  541. package/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
  542. package/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
  543. package/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
  544. package/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
  545. package/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
  546. package/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
  547. package/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
  548. package/templates/native-go-vue/frontend/src/i18n.ts +13 -0
  549. package/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
  550. package/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
  551. package/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
  552. package/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
  553. package/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
  554. package/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
  555. package/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
  556. package/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
  557. package/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
  558. package/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
  559. package/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
  560. package/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
  561. package/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
  562. package/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
  563. package/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
  564. package/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
  565. package/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
  566. package/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
  567. package/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
  568. package/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
  569. package/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
  570. package/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
  571. package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
  572. package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
  573. package/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
  574. package/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
  575. package/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
  576. package/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
  577. package/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
  578. package/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
@@ -8,10 +8,12 @@ A worker stores only a delegation ID and job ID, never session credentials.
8
8
  ## CLI assembly
9
9
 
10
10
  `init --with delegate` and `add delegate` apply base → jobs → delegate.
11
- The SDK registers `DelegateRoutes` using the trusted manifest scope and gives
12
- all seven methods below `authenticated` access through `sdk-permissions.json`.
13
- App-owned permissions remain in `permissions.json`; `app.status` is initialized
14
- as authenticated so ordinary users can mount their panels. The CLI binds both
11
+ The SDK registers `DelegateRoutes` using the trusted manifest scope and lists
12
+ all 17 delegate methods in `sdk-permissions.json`: `delegate.disable` and
13
+ `delegate.enable` require administrators, the others `authenticated`.
14
+ App-owned permissions remain in `permissions.json`. `init --with delegate` sets
15
+ `app.status` to authenticated so ordinary users can mount their panels;
16
+ `add delegate` leaves `permissions.json` unchanged. The CLI binds both
15
17
  policy files to the CGI build. SDK policy edits and overrides fail validation.
16
18
 
17
19
  `background.Job.DelegationID` is an optional field in the shared base store.
@@ -23,7 +25,7 @@ shared store before activating delegate.
23
25
  ```ts
24
26
  interface ExecutorSetup {
25
27
  status(): Promise<CapabilityStatus>
26
- authorize(password: string): Promise<CapabilityStatus>
28
+ authorize(password: string, selectedScope?: string): Promise<CapabilityStatus>
27
29
  control(action: 'start' | 'stop' | 'purge'): Promise<CapabilityStatus>
28
30
  }
29
31
  ```
@@ -140,3 +142,122 @@ The fixtures are temporary and are removed after each run.
140
142
  These tests do not claim DSM kernel ACL, owner, reboot, real task or real executor
141
143
  validation. CLI activation and real executor/setup integration belong to the other
142
144
  P2 workstreams.
145
+
146
+ ## Choose the scope at install and confirm it once
147
+
148
+ New `init` / `add delegate` projects default to `scope: install-selected`.
149
+ The DSM install wizard's native `api_store` combobox dynamically lists local
150
+ shares using the installer's administrator session (`SYNO.Core.Share list v1`).
151
+ A checkbox offers each user's `/home` instead; choosing a share never creates it
152
+ or grants its ACL to the package account. This wizard was measured on vt-nas
153
+ DSM 7.4 through a session-only SSH tunnel. Other DSM versions remain unverified.
154
+
155
+ Installation saves `{schema:1, scope}` in package-owned
156
+ `var/delegate-install.json`. It is **only a pre-selection**. The existing
157
+ administrator enable form displays it alongside the DSM password field. One
158
+ PasswordConfirm authorizes the pinned boot/control tasks and a one-time exact
159
+ selection task. Only the root executor writes
160
+ `/usr/local/etc/synopkgland/<pkg>/delegations/selected-scope.record`
161
+ (`schema`, `scope`, `generation`, root 0600). The package peer cannot call the
162
+ internal selection operation, even with an administrator cookie. Shipped
163
+ executor/policy pins lock the selection mode and operations; the chosen scope
164
+ is protected runtime state, so changing it does not rewrite shipped pins.
165
+
166
+ Settings uses this same form and `ctx.executor.authorize(password, scope)` to
167
+ change the scope. There is no extra dialog or step. A new scope generation
168
+ revokes existing grants and cancels pending saves under the publication fence.
169
+ Changing away and back never revives old grants. Existing destination files
170
+ remain. Selecting another directory for the same destination key replaces only
171
+ that person's previous grant for the key. Every person must select again after
172
+ scope changes. If the package draft differs, the UI shows both and follows the
173
+ protected value. Existing `scope: home` and `shared:<name>` manifests retain their
174
+ fixed-scope API and legacy TTL behavior. Dynamic selection requires the
175
+ `until-revoked` / `files.moveFromStaging` declaration.
176
+
177
+ A scope change on a running executor whose pins verify runs only the selection
178
+ task. It never restarts the executor, so a copy in flight ends `canceled` with
179
+ reason `scope-changed`, not `interrupted`. `authorize` waits about 20 seconds
180
+ for the protected readback. A `blocked` reply that carries `requested: {scope,
181
+ generation}` means the root task may still land: read `ctx.executor.status()`
182
+ (or `delegate.status`) until `selection.scope` equals `requested.scope` with a
183
+ `selection.generation` above `requested.generation` (applied); otherwise it was
184
+ not applied. Submitting the same scope again is safe: the task is pinned to the
185
+ current generation and an already selected scope is answered unchanged.
186
+
187
+ ## One typed destination lookup, online and offline
188
+
189
+ The generated Vue template contains the complete administrator setup, confirmed
190
+ scope, scope-limited NasPicker, personal destinations and operations, and admin
191
+ kill switch. Use its existing facade:
192
+
193
+ ```ts
194
+ import {createBackgroundSaveFacade} from './delegate/facade'
195
+ const sdk = createBackgroundSaveFacade(ctx)
196
+ const current = await sdk.destination('save')
197
+ // current.selection: {scope, root, generation} | null — protected executor evidence
198
+ // current.destination: {id, key, path, username, lifetime} | null — this caller only
199
+ // current.status: active | missing | reselection-required | needs-scope-confirmation | disabled
200
+ if (current.status === 'active') {
201
+ const ref = await sdk.exportExample({key: 'save', job_id: stableJobID})
202
+ // The generated My saves panel queries this reference; admission is not Saved.
203
+ }
204
+ ```
205
+
206
+ The authenticated CGI is `delegate.destination` with `{key}`; it verifies the
207
+ fresh DSM session and username+UID, configured key, protected scope/generation
208
+ and current grant. Neither browser storage nor the installation draft supplies
209
+ a destination. Errors or missing protected evidence disable new selections.
210
+
211
+ Go uses `service.Destination(ctx, caller, request, "save") (DestinationState,error)`.
212
+ Capture `current.Destination.ID` in the App's own job only when status is active.
213
+ After logout, a producer uses that ID with `service.MoveFromStaging(ctx, params)`.
214
+ It does not use the package draft, pass a virtual destination path, or retain
215
+ session credentials. The executor rechecks scope generation, account, grant,
216
+ directory identity and DSM ACL before writing as the user's nonzero UID.
217
+
218
+ The shipped **Save example file** button calls `delegate.example.export` with
219
+ `{key, job_id}`. `backend/internal/delegate/example.go` is a working producer:
220
+ it obtains this user's active destination, creates a small package-private JSON
221
+ file (0600) under staging, and invokes `MoveFromStaging`. Repeated job IDs repeat
222
+ the original request: they return the original operation, admit only one the
223
+ executor does not know, and never overwrite staging. Adapt this producer for
224
+ daemon/export jobs and keep its stable ID. An uncertain result has no automatic
225
+ retry; only a protected committed receipt means Saved.
226
+
227
+ If admission failed or its reply was lost, call `MoveFromStaging` again later
228
+ with the same params. It queries the original first and re-sends only an
229
+ operation the executor does not know, with the pinned source unchanged (at most
230
+ 10 possibly-delivered sends, 2 s backoff doubling to 5 min; the worker sweep
231
+ does the same). Retry on `EXECUTOR_UNAVAILABLE`, `EXECUTOR_TIMEOUT`,
232
+ `EXECUTOR_PROTOCOL`, `canceled`, `EXECUTOR_PAUSED`, `queue-full`,
233
+ `STORAGE_ERROR`, `ADMISSION_PENDING`, and on the package journal codes
234
+ `jobs_busy` (lock busy), `jobs_unavailable` (transient I/O) and `canceled` (the
235
+ caller's deadline or cancel ended the wait). None of these admitted anything a
236
+ retry could duplicate; while the journal is unavailable, a ref the executor
237
+ already knows still answers its state, so a committed move stays committed.
238
+ Terminal: executor refusals such as `APP_DENIED`, `DELEGATION_DENIED`,
239
+ `operation-conflict`, `disabled`, plus `STAGING_CHANGED`, `ADMISSION_EXHAUSTED`,
240
+ `spool_unsafe` and `journal_corrupt` (the package spool needs repair), and
241
+ `operation-not-found` for an accepted operation. See the delegate guide's Admission recovery table.
242
+
243
+ Cancel with the original reference (`CancelOperation`, or
244
+ `delegate.operations.cancel` from the UI); it is idempotent, so repeat it with
245
+ the same reference after a retryable error or a lost reply. `queued` becomes
246
+ `canceled` at once. A copy in flight answers `copying` with code
247
+ `CANCEL_REQUESTED`: accepted and durable, not finished. Poll `OperationStatus`
248
+ on the same reference until `canceled` (writer stopped, part removed, nothing
249
+ published, staging kept), `committed` (publication won; the file stays, drop only
250
+ the app record) or `uncertain` (a publish attempt failed first; keep querying).
251
+ The request survives executor crash, package stop/start and logout.
252
+ Revoke, scope change and disable store their reason (`grant-revoked`,
253
+ `scope-changed`, `integration-disabled`) the same way: a copy in flight answers
254
+ `CANCEL_REQUESTED` with it and settles `canceled` with it across a restart. A
255
+ copy the executor stops without a cancel ends `interrupted`/`EXECUTOR_PAUSED`
256
+ (`interrupted`/`interrupted` after a crash), never `WRITE_FAILED`. A cancel of
257
+ a reference not yet admitted leaves a `canceled` tombstone that a late or
258
+ recovered admission returns instead of copying, and a producer cancel is written
259
+ to the mirror first, so `MoveFromStaging` and the worker sweep forward it rather
260
+ than admit. See the delegate guide's Cancellation table.
261
+
262
+
263
+ The pinned scope-selection task also binds the protected generation observed before confirmation. The executor compares it under the publish lock and refuses stale tasks, so a retained task cannot replay an older selection after another confirmation.
@@ -12,12 +12,14 @@ import (
12
12
  "strconv"
13
13
  "syscall"
14
14
 
15
+ "dsmapp/internal/app"
15
16
  "dsmapp/internal/background"
16
17
  "dsmapp/internal/delegate"
17
18
  )
18
19
 
19
20
  // Set by `synopkgland build-spk` through -ldflags -X.
20
21
  var packageID = "dev"
22
+ var delegateScope, delegateOperationsJSON, delegateDestinationsJSON, delegateLifetime string
21
23
 
22
24
  func main() {
23
25
  log.SetFlags(0)
@@ -35,6 +37,11 @@ func main() {
35
37
  log.Printf("started as uid %s", strconv.Itoa(info.UID))
36
38
  dataDir := "/var/packages/" + packageID + "/var"
37
39
  service := &delegate.Service{Client: delegate.Local(packageID), Store: background.NewStore(dataDir + "/background"), StagingDir: dataDir + "/executor-staging"}
40
+ settings, err := app.ParseDelegateConfig(app.Config{DelegateScope: delegateScope, DelegateOperationsJSON: delegateOperationsJSON, DelegateDestinationsJSON: delegateDestinationsJSON, DelegateLifetime: delegateLifetime})
41
+ if err != nil {
42
+ log.Fatal(err)
43
+ }
44
+ service.Scope, service.Operations, service.Destinations, service.Lifetime = settings.Scope, settings.Operations, settings.Destinations, settings.Lifetime
38
45
  if err := service.Run(ctx, info); err != nil {
39
46
  log.Fatal(err)
40
47
  }
@@ -4,12 +4,22 @@ import (
4
4
  "dsmapp/internal/api"
5
5
  "dsmapp/internal/background"
6
6
  "dsmapp/internal/delegate"
7
+ "dsmapp/internal/filestation"
7
8
  "path/filepath"
8
9
  )
9
10
 
10
11
  // DelegateRoutes is appended by the CLI's delegate capability assembly.
11
12
  // scope comes from the trusted manifest, never an HTTP parameter.
12
13
  func DelegateRoutes(cfg Config, scope string) []api.Route {
13
- service := &delegate.Service{ExecutorDigest: cfg.ExecutorDigest, PolicyDigest: cfg.PolicyDigest, Client: delegate.Local(cfg.PackageID), Store: background.NewRequestStore(filepath.Join(cfg.DataDir, "background")), Scope: scope, StagingDir: filepath.Join(cfg.DataDir, "executor-staging")}
14
+ service := &delegate.Service{ExecutorDigest: cfg.ExecutorDigest, PolicyDigest: cfg.PolicyDigest, Client: delegate.Local(cfg.PackageID), Store: background.NewRequestStore(filepath.Join(cfg.DataDir, "background")), Scope: scope, StagingDir: filepath.Join(cfg.DataDir, "executor-staging"), InstallDraftPath: filepath.Join(cfg.DataDir, "delegate-install.json")}
15
+ settings, err := ParseDelegateConfig(cfg)
16
+ if err == nil {
17
+ service.Destinations, service.Operations, service.Lifetime = settings.Destinations, settings.Operations, settings.Lifetime
18
+ }
19
+ if cfg.SessionFiles != nil {
20
+ service.SessionFiles = cfg.SessionFiles
21
+ } else {
22
+ service.SessionFiles = filestation.Local(cfg.DataDir)
23
+ }
14
24
  return service.Routes()
15
25
  }
@@ -1,6 +1,20 @@
1
1
  package app
2
2
 
3
3
  func init() {
4
+ for method, params := range map[string]string{
5
+ "delegate.example.export": `{"key":"save","job_id":"example-1"}`,
6
+ "delegate.destination": `{"key":"save"}`,
7
+ "delegate.select_destination": `{"key":"save","path":"/home"}`,
8
+ "delegate.move_from_staging": `{"delegation_id":"grant","job_id":"export-1","staging":"a","name":"a","size":3}`,
9
+ "delegate.operations.get": `{"delegation_id":"grant","job_id":"export-1"}`,
10
+ "delegate.operations.list": `{}`,
11
+ "delegate.operations.cancel": `{"delegation_id":"grant","job_id":"export-1"}`,
12
+ "delegate.disable": `{}`, "delegate.enable": `{}`, "delegate.audit": `{}`,
13
+ } {
14
+ sampleParams[method] = params
15
+ sampleOutcome[method] = "session_required"
16
+ }
17
+
4
18
  sampleParams["delegate.status"] = `{}`
5
19
  sampleParams["delegate.create"] = `{"job_id":"job1","ops":["files.write"],"path":"/home","ttl_seconds":60}`
6
20
  sampleParams["delegate.list"] = `{}`
@@ -0,0 +1,270 @@
1
+ package background
2
+
3
+ import (
4
+ "bytes"
5
+ "context"
6
+ "encoding/json"
7
+ "errors"
8
+ "io"
9
+ "os"
10
+ "strings"
11
+ "time"
12
+
13
+ "golang.org/x/sys/unix"
14
+ )
15
+
16
+ // StagingIdentity identifies a package-owned source for cleanup only. It is
17
+ // never a grant, a UID selector for destination writes, or protected authority.
18
+ type StagingIdentity struct {
19
+ Device, Inode, ParentDevice, ParentInode, RootDevice, RootInode uint64
20
+ UID uint32
21
+ Size, ModifiedNS int64
22
+ }
23
+
24
+ type MoveBinding struct {
25
+ JobID string `json:"job_id"`
26
+ DelegationID string `json:"delegation_id"`
27
+ Params json.RawMessage `json:"params"`
28
+ Source StagingIdentity `json:"source"`
29
+ Settled bool `json:"settled,omitempty"`
30
+ CleanupDone bool `json:"cleanup_done,omitempty"`
31
+ Refusal string `json:"refusal,omitempty"`
32
+ // Phase records how far admission got. Older mirrors have none and are
33
+ // treated as possibly sent. Attempts counts sends that may have arrived.
34
+ Phase string `json:"phase,omitempty"`
35
+ Attempts int `json:"attempts,omitempty"`
36
+ NextAttempt int64 `json:"next_attempt,omitempty"`
37
+ // CancelRequested is the producer's durable cancel: it is forwarded until
38
+ // the executor answers, and admission is never sent again.
39
+ CancelRequested bool `json:"cancel_requested,omitempty"`
40
+ }
41
+
42
+ const (
43
+ MoveReserved = "reserved" // durable before transport; no request sent
44
+ MoveSent = "sent" // a request may have reached the executor
45
+ MoveAccepted = "accepted" // the executor returned the operation
46
+ )
47
+
48
+ const maxMoveMirrorBytes = 10 << 20
49
+
50
+ func moveBindingName(id string) string { return "move-" + sha256hex([]byte(id)) + ".json" }
51
+
52
+ func readMoveBinding(root *os.Root, id string) (MoveBinding, error) {
53
+ var out MoveBinding
54
+ f, err := root.OpenFile(moveBindingName(id), os.O_RDONLY|unix.O_NOFOLLOW, 0)
55
+ if err != nil {
56
+ return out, err
57
+ }
58
+ defer f.Close()
59
+ if err = checkPrivate(f); err != nil {
60
+ return out, err
61
+ }
62
+ data, err := io.ReadAll(io.LimitReader(f, 16385))
63
+ if err != nil || len(data) > 16384 || json.Unmarshal(data, &out) != nil || out.JobID != id || out.DelegationID == "" || !json.Valid(out.Params) {
64
+ return MoveBinding{}, ErrInvalid
65
+ }
66
+ return out, nil
67
+ }
68
+
69
+ func (s *Store) MoveBinding(ctx context.Context, id string) (MoveBinding, error) {
70
+ var out MoveBinding
71
+ err := s.withJournal(ctx, func(root *os.Root, _ *journal) (bool, error) {
72
+ var err error
73
+ out, err = readMoveBinding(root, id)
74
+ return false, err
75
+ })
76
+ return out, err
77
+ }
78
+
79
+ // ReserveMove fsyncs a mirror before admission. A process crash or ambiguous
80
+ // response leaves this reference for a status query first; only an operation
81
+ // the executor does not know is admitted again, through ClaimAdmission.
82
+ // A short spool lock covers metadata only, not a socket call or file copy.
83
+ func (s *Store) ReserveMove(ctx context.Context, in MoveBinding) (MoveBinding, bool, error) {
84
+ out := in
85
+ fresh := false
86
+ err := s.withJournal(ctx, func(root *os.Root, _ *journal) (bool, error) {
87
+ existing, err := readMoveBinding(root, in.JobID)
88
+ if err == nil {
89
+ if existing.DelegationID != in.DelegationID || !bytes.Equal(existing.Params, in.Params) {
90
+ return false, ErrKeyConflict
91
+ }
92
+ out = existing
93
+ return false, nil
94
+ }
95
+ if !errors.Is(err, os.ErrNotExist) {
96
+ return false, err
97
+ }
98
+ dir, err := root.Open(".")
99
+ if err != nil {
100
+ return false, err
101
+ }
102
+ defer dir.Close()
103
+ entries, err := dir.ReadDir(-1)
104
+ if err != nil {
105
+ return false, err
106
+ }
107
+ var used int64
108
+ for _, e := range entries {
109
+ if strings.HasPrefix(e.Name(), "move-") && strings.HasSuffix(e.Name(), ".json") {
110
+ info, err := e.Info()
111
+ if err != nil {
112
+ return false, err
113
+ }
114
+ used += info.Size()
115
+ }
116
+ }
117
+ // Completed/uncertain mirrors are retained for local replay prevention.
118
+ // The protected executor owns the authoritative operation/history quota.
119
+ encoded, err := json.Marshal(in)
120
+ if err != nil || len(encoded) > 16384 {
121
+ return false, ErrInvalid
122
+ }
123
+ if used+int64(len(encoded)) > maxMoveMirrorBytes {
124
+ return false, ErrQuota
125
+ }
126
+ if err = writeAtomic(root, moveBindingName(in.JobID), in); err != nil {
127
+ return false, err
128
+ }
129
+ fresh = true
130
+ return false, nil
131
+ })
132
+ return out, fresh, err
133
+ }
134
+
135
+ // updateMoveBinding rewrites one existing mirror under the spool lock when
136
+ // change reports a modification.
137
+ func (s *Store) updateMoveBinding(ctx context.Context, id string, change func(*MoveBinding) bool) error {
138
+ return s.withJournal(ctx, func(root *os.Root, _ *journal) (bool, error) {
139
+ in, err := readMoveBinding(root, id)
140
+ if err != nil || !change(&in) {
141
+ return false, err
142
+ }
143
+ return false, writeAtomic(root, moveBindingName(id), in)
144
+ })
145
+ }
146
+
147
+ // ClaimAdmission durably records one send before it happens. Concurrent
148
+ // callers serialize here: a claim is refused for accepted, settled, refused
149
+ // or exhausted mirrors, and before the backoff of the previous send ends.
150
+ func (s *Store) ClaimAdmission(ctx context.Context, id string, now time.Time, limit int, backoff func(int) time.Duration) (MoveBinding, bool, error) {
151
+ var out MoveBinding
152
+ claimed := false
153
+ err := s.updateMoveBinding(ctx, id, func(in *MoveBinding) bool {
154
+ out = *in
155
+ if in.Phase == MoveAccepted || in.Settled || in.CleanupDone || in.Refusal != "" || in.CancelRequested || in.Attempts >= limit || now.UnixNano() < in.NextAttempt {
156
+ return false
157
+ }
158
+ in.Phase, in.Attempts = MoveSent, in.Attempts+1
159
+ in.NextAttempt = now.Add(backoff(in.Attempts)).UnixNano()
160
+ out, claimed = *in, true
161
+ return true
162
+ })
163
+ return out, claimed, err
164
+ }
165
+
166
+ // ReleaseAdmission returns a claim the executor proved it did not admit, so
167
+ // the bound counts only sends that might have created an operation.
168
+ func (s *Store) ReleaseAdmission(ctx context.Context, id string) error {
169
+ return s.updateMoveBinding(ctx, id, func(in *MoveBinding) bool {
170
+ if in.Phase != MoveSent {
171
+ return false
172
+ }
173
+ in.Phase, in.Attempts, in.NextAttempt = MoveReserved, in.Attempts-1, 0
174
+ return true
175
+ })
176
+ }
177
+
178
+ // RequestMoveCancel durably records a cancel of the mirror bound to the grant.
179
+ func (s *Store) RequestMoveCancel(ctx context.Context, id, delegationID string) error {
180
+ return s.updateMoveBinding(ctx, id, func(in *MoveBinding) bool {
181
+ changed := in.DelegationID == delegationID && !in.CancelRequested
182
+ in.CancelRequested = in.CancelRequested || changed
183
+ return changed
184
+ })
185
+ }
186
+
187
+ func (s *Store) AcceptMove(ctx context.Context, id string) error {
188
+ return s.updateMoveBinding(ctx, id, func(in *MoveBinding) bool {
189
+ changed := in.Phase != MoveAccepted
190
+ in.Phase = MoveAccepted
191
+ return changed
192
+ })
193
+ }
194
+
195
+ func (s *Store) FinishMoveMirror(ctx context.Context, id string, cleaned bool, refusal string) error {
196
+ return s.updateMoveBinding(ctx, id, func(in *MoveBinding) bool {
197
+ in.CleanupDone = in.CleanupDone || cleaned
198
+ in.Settled = in.Settled || cleaned
199
+ if refusal != "" {
200
+ in.Refusal = refusal
201
+ }
202
+ return true
203
+ })
204
+ }
205
+
206
+ func (s *Store) moveBindings(ctx context.Context) ([]MoveBinding, error) {
207
+ out := []MoveBinding{}
208
+ err := s.withJournal(ctx, func(root *os.Root, _ *journal) (bool, error) {
209
+ dir, err := root.Open(".")
210
+ if err != nil {
211
+ return false, err
212
+ }
213
+ defer dir.Close()
214
+ entries, err := dir.ReadDir(-1)
215
+ if err != nil {
216
+ return false, err
217
+ }
218
+ for _, entry := range entries {
219
+ if !strings.HasPrefix(entry.Name(), "move-") || !strings.HasSuffix(entry.Name(), ".json") {
220
+ continue
221
+ }
222
+ // Decode the bounded record to recover its non-path job key; verify it
223
+ // again through readMoveBinding before trusting even this local mirror.
224
+ f, err := root.OpenFile(entry.Name(), os.O_RDONLY|unix.O_NOFOLLOW, 0)
225
+ if err != nil {
226
+ return false, err
227
+ }
228
+ err = checkPrivate(f)
229
+ data, readErr := io.ReadAll(io.LimitReader(f, 16385))
230
+ f.Close()
231
+ var key struct {
232
+ JobID string `json:"job_id"`
233
+ }
234
+ if err != nil || readErr != nil || len(data) > 16384 || json.Unmarshal(data, &key) != nil || entry.Name() != moveBindingName(key.JobID) {
235
+ return false, ErrInvalid
236
+ }
237
+ binding, err := readMoveBinding(root, key.JobID)
238
+ if err != nil {
239
+ return false, err
240
+ }
241
+ out = append(out, binding)
242
+ }
243
+ return false, nil
244
+ })
245
+ return out, err
246
+ }
247
+
248
+ func (s *Store) PendingMoves(ctx context.Context) ([]MoveBinding, error) {
249
+ bindings, err := s.moveBindings(ctx)
250
+ out := []MoveBinding{}
251
+ for _, binding := range bindings {
252
+ if !binding.Settled && !binding.CleanupDone && binding.Refusal == "" {
253
+ out = append(out, binding)
254
+ }
255
+ }
256
+ return out, err
257
+ }
258
+
259
+ // MoveBindings includes settled/refused history. Callers must apply fresh
260
+ // owner authorization; package mirrors never confer destination authority.
261
+ func (s *Store) MoveBindings(ctx context.Context) ([]MoveBinding, error) { return s.moveBindings(ctx) }
262
+
263
+ // Settled mirrors remain available to explicit status calls and idempotency,
264
+ // but terminal operations do not make the worker poll history indefinitely.
265
+ func (s *Store) SettleMoveMirror(ctx context.Context, id string) error {
266
+ return s.updateMoveBinding(ctx, id, func(in *MoveBinding) bool {
267
+ in.Settled = true
268
+ return true
269
+ })
270
+ }