ecoportal-api-graphql 1.3.5 → 1.3.9

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 (499) hide show
  1. checksums.yaml +4 -4
  2. data/.ai-assistance/bridge/CLAUDE.md +338 -0
  3. data/.ai-assistance/bridge/archive/.gitkeep +0 -0
  4. data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.inbox.md +29 -0
  5. data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.outbox.md +18 -0
  6. data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.inbox.md +42 -0
  7. data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.outbox.md +115 -0
  8. data/.ai-assistance/bridge/context/gemini-review-prompt.txt +48 -0
  9. data/.ai-assistance/bridge/context/gemini-review-response.md +104 -0
  10. data/.ai-assistance/bridge/context/project.md +42 -0
  11. data/.ai-assistance/bridge/inbox/.gitkeep +0 -0
  12. data/.ai-assistance/bridge/outbox/.gitkeep +0 -0
  13. data/.ai-assistance/bridge/outbox/request-for-standards-discovery.md +48 -0
  14. data/.ai-assistance/bridge/queue/.gitkeep +1 -0
  15. data/.ai-assistance/capabilities/CLAUDE.md +27 -0
  16. data/.ai-assistance/capabilities/assumptions-log.md +80 -0
  17. data/.ai-assistance/capabilities/code.md +47 -0
  18. data/.ai-assistance/capabilities/connectors.md +37 -0
  19. data/.ai-assistance/capabilities/cowork.md +55 -0
  20. data/.ai-assistance/code/OVERVIEW.md +155 -0
  21. data/.ai-assistance/code/data_fields.md +242 -0
  22. data/.ai-assistance/code/dependencies.md +151 -0
  23. data/.ai-assistance/code/diff_as_input.md +234 -0
  24. data/.ai-assistance/code/diff_service_deep_dive.md +192 -0
  25. data/.ai-assistance/code/ecoPortal_architecture/00_overview_and_index.md +55 -0
  26. data/.ai-assistance/code/ecoPortal_architecture/01_terminology_dictionary.md +181 -0
  27. data/.ai-assistance/code/ecoPortal_architecture/02_data_model.md +192 -0
  28. data/.ai-assistance/code/ecoPortal_architecture/03_api_layers.md +147 -0
  29. data/.ai-assistance/code/ecoPortal_architecture/04_graphql_queries_mutations.md +277 -0
  30. data/.ai-assistance/code/ecoPortal_architecture/05_page_workflows.md +200 -0
  31. data/.ai-assistance/code/ecoPortal_architecture/06_search_and_filters.md +228 -0
  32. data/.ai-assistance/code/ecoPortal_architecture/07_data_fields.md +197 -0
  33. data/.ai-assistance/code/ecoPortal_architecture/08_stages_sections.md +243 -0
  34. data/.ai-assistance/code/ecoPortal_architecture/09_people_contractors_locations.md +196 -0
  35. data/.ai-assistance/code/ecoPortal_architecture/10_forces_workflow_builder.md +132 -0
  36. data/.ai-assistance/code/ecoPortal_architecture/11_integration_gems.md +187 -0
  37. data/.ai-assistance/code/ecoPortal_architecture/12_ai_documentation_sources_gaps.md +236 -0
  38. data/.ai-assistance/code/ecoPortal_architecture/13_ai_infrastructure.md +183 -0
  39. data/.ai-assistance/code/ecoportal_schema_reference.md +240 -0
  40. data/.ai-assistance/code/graphql_domain_knowledge.md +230 -0
  41. data/.ai-assistance/code/refactoring/datafield-readwrite-shape-asymmetry.md +71 -0
  42. data/.ai-assistance/code/refactoring/opportunities.md +251 -0
  43. data/.ai-assistance/code/schema_analysis.md +321 -0
  44. data/.ai-assistance/code/search_filters.md +868 -0
  45. data/.ai-assistance/code/spec_coverage.md +73 -0
  46. data/.ai-assistance/code/workflow-command-guide.md +438 -0
  47. data/.ai-assistance/code/workflow-space.md +353 -0
  48. data/.ai-assistance/conventions/CLAUDE.md +30 -0
  49. data/.ai-assistance/conventions/code-working-tree-protocol.md +199 -0
  50. data/.ai-assistance/conventions/gitignore-rules.md +42 -0
  51. data/.ai-assistance/conventions/permission-guidance.md +120 -0
  52. data/.ai-assistance/integrations/README.md +70 -0
  53. data/.ai-assistance/integrations/gitkraken-mcp.md +107 -0
  54. data/.ai-assistance/integrations/gitlab-mcp.md +123 -0
  55. data/.ai-assistance/integrations/local-git.md +60 -0
  56. data/.ai-assistance/local_paths.example.md +17 -0
  57. data/.ai-assistance/projects/TODO.md +97 -0
  58. data/.ai-assistance/projects/api-v2-to-graphql-migration/DECISIONS.md +168 -0
  59. data/.ai-assistance/projects/api-v2-to-graphql-migration/INTENT.md +60 -0
  60. data/.ai-assistance/projects/api-v2-to-graphql-migration/TODO.md +267 -0
  61. data/.ai-assistance/projects/api-v2-to-graphql-migration/UPSTREAM.md +53 -0
  62. data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/csv-template-pipeline-design.md +102 -0
  63. data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/cutover-usecase-gap-audit.md +139 -0
  64. data/.ai-assistance/projects/dynamic-model-generation/INTENT.md +93 -0
  65. data/.ai-assistance/projects/eco-helpers-compat/INTENT.md +244 -0
  66. data/.ai-assistance/projects/eco-helpers-compat/MIGRATION_GUIDE.md +266 -0
  67. data/.ai-assistance/projects/eco-helpers-compat/TODO.md +86 -0
  68. data/.ai-assistance/projects/ecoportal-api-v2-doublemodel-review/INTENT.md +101 -0
  69. data/.ai-assistance/projects/graphql-agent/GAP_ANALYSIS.md +177 -0
  70. data/.ai-assistance/projects/ooze-graphql-native-migration/DECISIONS.md +161 -0
  71. data/.ai-assistance/projects/ooze-graphql-native-migration/INTENT.md +125 -0
  72. data/.ai-assistance/projects/ooze-graphql-native-migration/RISKS.md +126 -0
  73. data/.ai-assistance/projects/ooze-graphql-native-migration/TODO.md +256 -0
  74. data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-06-30-cutover-workflow-deep-review.md +122 -0
  75. data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-07-01-forces-via-workflow-commands-miss-rca.md +148 -0
  76. data/.ai-assistance/projects/page-model/DECISIONS.md +245 -0
  77. data/.ai-assistance/projects/page-model/TODO.md +190 -0
  78. data/.ai-assistance/projects/search-filter-builder/INTENT.md +107 -0
  79. data/.ai-assistance/projects/search-filter-builder/TODO.md +131 -0
  80. data/.ai-assistance/projects/template-maintenance/DESIGN.md +134 -0
  81. data/.ai-assistance/projects/workflow-space/TODO.md +213 -0
  82. data/.ai-assistance/reinstall-claude-desktop-windows.md +136 -0
  83. data/.ai-assistance/scripts/CLAUDE.md +150 -0
  84. data/.ai-assistance/scripts/bridge-init.sh +86 -0
  85. data/.ai-assistance/scripts/bridge-status.sh +44 -0
  86. data/.ai-assistance/scripts/capabilities-check.ts +104 -0
  87. data/.ai-assistance/scripts/check-outbox.sh +43 -0
  88. data/.ai-assistance/scripts/dep_graph.rb +91 -0
  89. data/.ai-assistance/scripts/lock-acquire.sh +103 -0
  90. data/.ai-assistance/scripts/lock-multi.sh +124 -0
  91. data/.ai-assistance/scripts/lock-queue.sh +94 -0
  92. data/.ai-assistance/scripts/setup-mcps.test.ts +188 -0
  93. data/.ai-assistance/scripts/setup-mcps.ts +234 -0
  94. data/.ai-assistance/scripts/task-complete.ts +74 -0
  95. data/.ai-assistance/scripts/task-create.ts +75 -0
  96. data/.ai-assistance/scripts/task-read.ts +125 -0
  97. data/.ai-assistance/scripts/token-logger.js +220 -0
  98. data/.ai-assistance/scripts/token-report.ts +158 -0
  99. data/.ai-assistance/scripts/token-session-start.js +66 -0
  100. data/.ai-assistance/skills/ai-instructions/SKILL.md +48 -0
  101. data/.ai-assistance/skills/code-specs/SKILL.md +69 -0
  102. data/.ai-assistance/skills/corporate-policies/SKILL.md +201 -0
  103. data/.ai-assistance/skills/dep-graph/SKILL.md +139 -0
  104. data/.ai-assistance/skills/ep-ai-manager/SKILL.md +417 -0
  105. data/.ai-assistance/skills/gemini-assist/SKILL.md +63 -0
  106. data/.ai-assistance/skills/gemini-assist/gemini-mcp-server.js +205 -0
  107. data/.ai-assistance/skills/gemini-assist/gemini_ask.py +1 -0
  108. data/.ai-assistance/skills/gemini-assist/gemini_ask.rb +240 -0
  109. data/.ai-assistance/skills/gemini-assist/prompts/cycle_end_review.txt +25 -0
  110. data/.ai-assistance/skills/graphql-schema-analysis/SKILL.md +261 -0
  111. data/.ai-assistance/skills/project-cycle/SKILL.md +177 -0
  112. data/.ai-assistance/skills/refactor/SKILL.md +62 -0
  113. data/.ai-assistance/skills/rubocop/SKILL.md +93 -0
  114. data/.ai-assistance/skills/ruby-scripting/SKILL.md +215 -0
  115. data/.ai-assistance/skills/spec-generation/SKILL.md +72 -0
  116. data/.ai-assistance/standards-version.json +21 -0
  117. data/.ai-assistance/token-budget.json +32 -0
  118. data/.ai-assistance/version.json +39 -0
  119. data/.claude/settings.json +146 -0
  120. data/.env.example +18 -0
  121. data/.gitattributes +15 -0
  122. data/.gitignore +13 -0
  123. data/.rubocop.yml +121 -97
  124. data/CHANGELOG.md +673 -477
  125. data/CLAUDE.md +232 -0
  126. data/Gemfile +30 -6
  127. data/Rakefile +90 -38
  128. data/docs/worklog.md +574 -0
  129. data/ecoportal-api-graphql.gemspec +40 -40
  130. data/lib/ecoportal/api/common/graphql/CLAUDE.md +36 -0
  131. data/lib/ecoportal/api/common/graphql/client.rb +1 -1
  132. data/lib/ecoportal/api/common/graphql/http_client.rb +35 -3
  133. data/lib/ecoportal/api/common/graphql/model/CLAUDE.md +28 -0
  134. data/lib/ecoportal/api/common/graphql/model/as_input.rb +8 -5
  135. data/lib/ecoportal/api/common/graphql/model/diffable/classic_diff_service.rb +3 -1
  136. data/lib/ecoportal/api/common/graphql/model/diffable/diff_service.rb +31 -23
  137. data/lib/ecoportal/api/common/graphql/model/diffable/hash_diff_nesting.rb +54 -1
  138. data/lib/ecoportal/api/graphql/CLAUDE.md +37 -0
  139. data/lib/ecoportal/api/graphql/base/CLAUDE.md +50 -0
  140. data/lib/ecoportal/api/graphql/base/ai_summary_version.rb +17 -0
  141. data/lib/ecoportal/api/graphql/base/delta_result.rb +16 -0
  142. data/lib/ecoportal/api/graphql/base/force/binding.rb +19 -0
  143. data/lib/ecoportal/api/graphql/base/force/binding_collection.rb +62 -0
  144. data/lib/ecoportal/api/graphql/base/force/collection.rb +47 -0
  145. data/lib/ecoportal/api/graphql/base/force.rb +65 -0
  146. data/lib/ecoportal/api/graphql/base/kickstand/job.rb +17 -0
  147. data/lib/ecoportal/api/graphql/base/kickstand/workflow.rb +18 -0
  148. data/lib/ecoportal/api/graphql/base/kickstand.rb +13 -0
  149. data/lib/ecoportal/api/graphql/base/page/basic.rb +38 -0
  150. data/lib/ecoportal/api/graphql/base/page/data_field/actions_list.rb +9 -0
  151. data/lib/ecoportal/api/graphql/base/page/data_field/ai_summary.rb +18 -0
  152. data/lib/ecoportal/api/graphql/base/page/data_field/checklist.rb +29 -0
  153. data/lib/ecoportal/api/graphql/base/page/data_field/collection.rb +112 -0
  154. data/lib/ecoportal/api/graphql/base/page/data_field/contractor_entities.rb +28 -0
  155. data/lib/ecoportal/api/graphql/base/page/data_field/cross_reference.rb +54 -0
  156. data/lib/ecoportal/api/graphql/base/page/data_field/date_field.rb +23 -0
  157. data/lib/ecoportal/api/graphql/base/page/data_field/file_field.rb +25 -0
  158. data/lib/ecoportal/api/graphql/base/page/data_field/gauge.rb +19 -0
  159. data/lib/ecoportal/api/graphql/base/page/data_field/geo.rb +24 -0
  160. data/lib/ecoportal/api/graphql/base/page/data_field/image_gallery.rb +24 -0
  161. data/lib/ecoportal/api/graphql/base/page/data_field/law.rb +8 -0
  162. data/lib/ecoportal/api/graphql/base/page/data_field/mailbox.rb +9 -0
  163. data/lib/ecoportal/api/graphql/base/page/data_field/number.rb +20 -0
  164. data/lib/ecoportal/api/graphql/base/page/data_field/people.rb +35 -0
  165. data/lib/ecoportal/api/graphql/base/page/data_field/plain_text.rb +17 -0
  166. data/lib/ecoportal/api/graphql/base/page/data_field/rich_text.rb +26 -0
  167. data/lib/ecoportal/api/graphql/base/page/data_field/select.rb +41 -0
  168. data/lib/ecoportal/api/graphql/base/page/data_field/signature.rb +9 -0
  169. data/lib/ecoportal/api/graphql/base/page/data_field/smart_fill.rb +17 -0
  170. data/lib/ecoportal/api/graphql/base/page/data_field/table.rb +9 -0
  171. data/lib/ecoportal/api/graphql/base/page/data_field/tag_field.rb +21 -0
  172. data/lib/ecoportal/api/graphql/base/page/data_field.rb +137 -12
  173. data/lib/ecoportal/api/graphql/base/page/phased/stage.rb +68 -14
  174. data/lib/ecoportal/api/graphql/base/page/phased.rb +1 -0
  175. data/lib/ecoportal/api/graphql/base/page/section.rb +36 -0
  176. data/lib/ecoportal/api/graphql/base/page/section_collection.rb +79 -0
  177. data/lib/ecoportal/api/graphql/base/page.rb +2 -0
  178. data/lib/ecoportal/api/graphql/base/pages_workflow/action_type_selection.rb +17 -0
  179. data/lib/ecoportal/api/graphql/base/pages_workflow/callback_type.rb +28 -0
  180. data/lib/ecoportal/api/graphql/base/pages_workflow/command_change.rb +17 -0
  181. data/lib/ecoportal/api/graphql/base/pages_workflow/command_change_message.rb +15 -0
  182. data/lib/ecoportal/api/graphql/base/pages_workflow/command_es_change.rb +17 -0
  183. data/lib/ecoportal/api/graphql/base/pages_workflow/command_interface.rb +36 -0
  184. data/lib/ecoportal/api/graphql/base/pages_workflow/email_config.rb +18 -0
  185. data/lib/ecoportal/api/graphql/base/pages_workflow/escalation_level.rb +19 -0
  186. data/lib/ecoportal/api/graphql/base/pages_workflow/in_system_config.rb +16 -0
  187. data/lib/ecoportal/api/graphql/base/pages_workflow/mailbox_field_selection.rb +17 -0
  188. data/lib/ecoportal/api/graphql/base/pages_workflow/operation_interface.rb +39 -0
  189. data/lib/ecoportal/api/graphql/base/pages_workflow/operations/assign_to.rb +27 -0
  190. data/lib/ecoportal/api/graphql/base/pages_workflow/operations/create_page.rb +21 -0
  191. data/lib/ecoportal/api/graphql/base/pages_workflow/operations/send_notification.rb +30 -0
  192. data/lib/ecoportal/api/graphql/base/pages_workflow/people_field_selection.rb +17 -0
  193. data/lib/ecoportal/api/graphql/base/pages_workflow/recipient_config.rb +34 -0
  194. data/lib/ecoportal/api/graphql/base/pages_workflow/register_field.rb +17 -0
  195. data/lib/ecoportal/api/graphql/base/pages_workflow/task_config_selection.rb +17 -0
  196. data/lib/ecoportal/api/graphql/base/pages_workflow/time_delay_config.rb +16 -0
  197. data/lib/ecoportal/api/graphql/base/pages_workflow/trigger_interface.rb +26 -0
  198. data/lib/ecoportal/api/graphql/base/pages_workflow/triggers/conditional_logic.rb +17 -0
  199. data/lib/ecoportal/api/graphql/base/pages_workflow/user_selection.rb +16 -0
  200. data/lib/ecoportal/api/graphql/base/pages_workflow.rb +35 -0
  201. data/lib/ecoportal/api/graphql/base/preset_view.rb +17 -0
  202. data/lib/ecoportal/api/graphql/base/preview_page.rb +23 -0
  203. data/lib/ecoportal/api/graphql/base/register.rb +18 -0
  204. data/lib/ecoportal/api/graphql/base.rb +11 -0
  205. data/lib/ecoportal/api/graphql/builder/CLAUDE.md +65 -0
  206. data/lib/ecoportal/api/graphql/builder/kickstand.rb +73 -0
  207. data/lib/ecoportal/api/graphql/builder/page.rb +210 -41
  208. data/lib/ecoportal/api/graphql/builder/register/preset_view.rb +84 -0
  209. data/lib/ecoportal/api/graphql/builder/register.rb +27 -19
  210. data/lib/ecoportal/api/graphql/builder/template.rb +80 -0
  211. data/lib/ecoportal/api/graphql/builder.rb +2 -0
  212. data/lib/ecoportal/api/graphql/compat/filter_translator.rb +107 -0
  213. data/lib/ecoportal/api/graphql/compat/page_reference.rb +23 -0
  214. data/lib/ecoportal/api/graphql/compat/pages.rb +212 -0
  215. data/lib/ecoportal/api/graphql/compat/registers.rb +84 -0
  216. data/lib/ecoportal/api/graphql/compat/response.rb +35 -0
  217. data/lib/ecoportal/api/graphql/compat/search_results.rb +33 -0
  218. data/lib/ecoportal/api/graphql/compat/stage_collection.rb +70 -0
  219. data/lib/ecoportal/api/graphql/compat/stage_view.rb +76 -0
  220. data/lib/ecoportal/api/graphql/compat.rb +17 -0
  221. data/lib/ecoportal/api/graphql/concerns/data_field_access.rb +71 -0
  222. data/lib/ecoportal/api/graphql/concerns/deprecation.rb +20 -0
  223. data/lib/ecoportal/api/graphql/concerns/fragment_definitions.rb +21 -28
  224. data/lib/ecoportal/api/graphql/concerns/page_compat.rb +51 -0
  225. data/lib/ecoportal/api/graphql/concerns/snake_camel_access.rb +60 -0
  226. data/lib/ecoportal/api/graphql/concerns.rb +4 -0
  227. data/lib/ecoportal/api/graphql/connection/page.rb +11 -0
  228. data/lib/ecoportal/api/graphql/connection/pages_workflow_command.rb +13 -0
  229. data/lib/ecoportal/api/graphql/connection/preset_view.rb +11 -0
  230. data/lib/ecoportal/api/graphql/connection/preview_page.rb +11 -0
  231. data/lib/ecoportal/api/graphql/connection.rb +4 -0
  232. data/lib/ecoportal/api/graphql/file_upload/client.rb +181 -0
  233. data/lib/ecoportal/api/graphql/file_upload.rb +10 -0
  234. data/lib/ecoportal/api/graphql/fragment/action.rb +1 -1
  235. data/lib/ecoportal/api/graphql/fragment/action_category.rb +1 -1
  236. data/lib/ecoportal/api/graphql/fragment/contractor_entity.rb +1 -1
  237. data/lib/ecoportal/api/graphql/fragment/force.rb +30 -0
  238. data/lib/ecoportal/api/graphql/fragment/location_draft.rb +2 -2
  239. data/lib/ecoportal/api/graphql/fragment/location_node.rb +1 -1
  240. data/lib/ecoportal/api/graphql/fragment/locations_error.rb +1 -1
  241. data/lib/ecoportal/api/graphql/fragment/page.rb +85 -0
  242. data/lib/ecoportal/api/graphql/fragment/pages/common_page_union.rb +395 -0
  243. data/lib/ecoportal/api/graphql/fragment/pages.rb +15 -0
  244. data/lib/ecoportal/api/graphql/fragment/pages_workflow.rb +172 -0
  245. data/lib/ecoportal/api/graphql/fragment/pagination.rb +1 -1
  246. data/lib/ecoportal/api/graphql/fragment.rb +37 -27
  247. data/lib/ecoportal/api/graphql/input/contractor_entity/update.rb +25 -0
  248. data/lib/ecoportal/api/graphql/input/delta_input.rb +16 -0
  249. data/lib/ecoportal/api/graphql/input/page/archive.rb +14 -0
  250. data/lib/ecoportal/api/graphql/input/page/build_from_template.rb +13 -0
  251. data/lib/ecoportal/api/graphql/input/page/create_draft.rb +13 -0
  252. data/lib/ecoportal/api/graphql/input/page/create_from_template.rb +18 -0
  253. data/lib/ecoportal/api/graphql/input/page/delete_draft.rb +13 -0
  254. data/lib/ecoportal/api/graphql/input/page/publish_draft.rb +13 -0
  255. data/lib/ecoportal/api/graphql/input/page/review_task.rb +14 -0
  256. data/lib/ecoportal/api/graphql/input/page/unarchive.rb +14 -0
  257. data/lib/ecoportal/api/graphql/input/page/update.rb +140 -0
  258. data/lib/ecoportal/api/graphql/input/page.rb +26 -0
  259. data/lib/ecoportal/api/graphql/input/preset_view/create.rb +18 -0
  260. data/lib/ecoportal/api/graphql/input/preset_view/permission.rb +16 -0
  261. data/lib/ecoportal/api/graphql/input/preset_view/update.rb +16 -0
  262. data/lib/ecoportal/api/graphql/input/preset_view.rb +14 -0
  263. data/lib/ecoportal/api/graphql/input/register/create.rb +18 -0
  264. data/lib/ecoportal/api/graphql/input/register/update.rb +15 -0
  265. data/lib/ecoportal/api/graphql/input/register.rb +13 -0
  266. data/lib/ecoportal/api/graphql/input/search_conf/ai_generator.rb +234 -0
  267. data/lib/ecoportal/api/graphql/input/search_conf.rb +367 -0
  268. data/lib/ecoportal/api/graphql/input/variable_binding.rb +20 -0
  269. data/lib/ecoportal/api/graphql/input/workflow_command/add_action_tag.rb +18 -0
  270. data/lib/ecoportal/api/graphql/input/workflow_command/add_binding.rb +18 -0
  271. data/lib/ecoportal/api/graphql/input/workflow_command/add_comment_tagging_user_group.rb +18 -0
  272. data/lib/ecoportal/api/graphql/input/workflow_command/add_default_direct_strategy_user.rb +18 -0
  273. data/lib/ecoportal/api/graphql/input/workflow_command/add_default_strategy.rb +18 -0
  274. data/lib/ecoportal/api/graphql/input/workflow_command/add_direct_strategy_user.rb +18 -0
  275. data/lib/ecoportal/api/graphql/input/workflow_command/add_field.rb +18 -0
  276. data/lib/ecoportal/api/graphql/input/workflow_command/add_force.rb +18 -0
  277. data/lib/ecoportal/api/graphql/input/workflow_command/add_gauge_field_stop.rb +19 -0
  278. data/lib/ecoportal/api/graphql/input/workflow_command/add_linked_field_config.rb +23 -0
  279. data/lib/ecoportal/api/graphql/input/workflow_command/add_linked_helper.rb +18 -0
  280. data/lib/ecoportal/api/graphql/input/workflow_command/add_operation.rb +18 -0
  281. data/lib/ecoportal/api/graphql/input/workflow_command/add_operation_direct_strategy_user.rb +18 -0
  282. data/lib/ecoportal/api/graphql/input/workflow_command/add_operation_strategy.rb +18 -0
  283. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_action_type.rb +18 -0
  284. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_filter.rb +18 -0
  285. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_people_field.rb +18 -0
  286. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_task_config.rb +18 -0
  287. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_user.rb +18 -0
  288. data/lib/ecoportal/api/graphql/input/workflow_command/add_scheduled_callback.rb +23 -0
  289. data/lib/ecoportal/api/graphql/input/workflow_command/add_scheduled_callback_action.rb +18 -0
  290. data/lib/ecoportal/api/graphql/input/workflow_command/add_section.rb +18 -0
  291. data/lib/ecoportal/api/graphql/input/workflow_command/add_select_field_option.rb +19 -0
  292. data/lib/ecoportal/api/graphql/input/workflow_command/add_stage.rb +18 -0
  293. data/lib/ecoportal/api/graphql/input/workflow_command/add_stage_section.rb +18 -0
  294. data/lib/ecoportal/api/graphql/input/workflow_command/add_stage_tag.rb +18 -0
  295. data/lib/ecoportal/api/graphql/input/workflow_command/add_strategy.rb +18 -0
  296. data/lib/ecoportal/api/graphql/input/workflow_command/add_task.rb +18 -0
  297. data/lib/ecoportal/api/graphql/input/workflow_command/add_task_assignment_user_group.rb +18 -0
  298. data/lib/ecoportal/api/graphql/input/workflow_command/add_workflow_callback.rb +18 -0
  299. data/lib/ecoportal/api/graphql/input/workflow_command/collapse_section.rb +18 -0
  300. data/lib/ecoportal/api/graphql/input/workflow_command/edit_binding.rb +18 -0
  301. data/lib/ecoportal/api/graphql/input/workflow_command/edit_creator_permissions.rb +18 -0
  302. data/lib/ecoportal/api/graphql/input/workflow_command/edit_default_strategy.rb +18 -0
  303. data/lib/ecoportal/api/graphql/input/workflow_command/edit_field_configuration.rb +21 -0
  304. data/lib/ecoportal/api/graphql/input/workflow_command/edit_force.rb +18 -0
  305. data/lib/ecoportal/api/graphql/input/workflow_command/edit_gauge_field_stop.rb +19 -0
  306. data/lib/ecoportal/api/graphql/input/workflow_command/edit_linked_field_config.rb +19 -0
  307. data/lib/ecoportal/api/graphql/input/workflow_command/edit_linked_helper.rb +18 -0
  308. data/lib/ecoportal/api/graphql/input/workflow_command/edit_operation.rb +18 -0
  309. data/lib/ecoportal/api/graphql/input/workflow_command/edit_operation_strategy.rb +18 -0
  310. data/lib/ecoportal/api/graphql/input/workflow_command/edit_page.rb +28 -0
  311. data/lib/ecoportal/api/graphql/input/workflow_command/edit_page_creator_permissions.rb +18 -0
  312. data/lib/ecoportal/api/graphql/input/workflow_command/edit_reminder.rb +18 -0
  313. data/lib/ecoportal/api/graphql/input/workflow_command/edit_required_sign_offs.rb +18 -0
  314. data/lib/ecoportal/api/graphql/input/workflow_command/edit_restrict_comment_tagging.rb +18 -0
  315. data/lib/ecoportal/api/graphql/input/workflow_command/edit_restrict_task_assignment.rb +18 -0
  316. data/lib/ecoportal/api/graphql/input/workflow_command/edit_scheduled_callback.rb +22 -0
  317. data/lib/ecoportal/api/graphql/input/workflow_command/edit_section_header.rb +18 -0
  318. data/lib/ecoportal/api/graphql/input/workflow_command/edit_select_field_option.rb +19 -0
  319. data/lib/ecoportal/api/graphql/input/workflow_command/edit_stage.rb +18 -0
  320. data/lib/ecoportal/api/graphql/input/workflow_command/edit_strategy.rb +18 -0
  321. data/lib/ecoportal/api/graphql/input/workflow_command/edit_task_due.rb +18 -0
  322. data/lib/ecoportal/api/graphql/input/workflow_command/edit_trigger.rb +18 -0
  323. data/lib/ecoportal/api/graphql/input/workflow_command/expand_section.rb +18 -0
  324. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/contractor_entities.rb +24 -0
  325. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/cross_reference.rb +23 -0
  326. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/date.rb +20 -0
  327. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/gauge.rb +20 -0
  328. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/image_gallery.rb +20 -0
  329. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/location_field.rb +24 -0
  330. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/people.rb +24 -0
  331. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/plain_text.rb +20 -0
  332. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/rich_text.rb +20 -0
  333. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/select.rb +20 -0
  334. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/signature.rb +20 -0
  335. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/table.rb +25 -0
  336. data/lib/ecoportal/api/graphql/input/workflow_command/move_field.rb +18 -0
  337. data/lib/ecoportal/api/graphql/input/workflow_command/move_stage.rb +18 -0
  338. data/lib/ecoportal/api/graphql/input/workflow_command/remove_action_tag.rb +18 -0
  339. data/lib/ecoportal/api/graphql/input/workflow_command/remove_binding.rb +18 -0
  340. data/lib/ecoportal/api/graphql/input/workflow_command/remove_callback.rb +18 -0
  341. data/lib/ecoportal/api/graphql/input/workflow_command/remove_comment_tagging_user_group.rb +18 -0
  342. data/lib/ecoportal/api/graphql/input/workflow_command/remove_default_direct_strategy_user.rb +18 -0
  343. data/lib/ecoportal/api/graphql/input/workflow_command/remove_default_strategy.rb +18 -0
  344. data/lib/ecoportal/api/graphql/input/workflow_command/remove_direct_strategy_user.rb +18 -0
  345. data/lib/ecoportal/api/graphql/input/workflow_command/remove_field.rb +18 -0
  346. data/lib/ecoportal/api/graphql/input/workflow_command/remove_force.rb +18 -0
  347. data/lib/ecoportal/api/graphql/input/workflow_command/remove_gauge_field_stop.rb +17 -0
  348. data/lib/ecoportal/api/graphql/input/workflow_command/remove_linked_field_config.rb +17 -0
  349. data/lib/ecoportal/api/graphql/input/workflow_command/remove_linked_helper.rb +18 -0
  350. data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation.rb +18 -0
  351. data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation_direct_strategy_user.rb +18 -0
  352. data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation_strategy.rb +18 -0
  353. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_action_type.rb +18 -0
  354. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_filter.rb +18 -0
  355. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_people_field.rb +18 -0
  356. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_task_config.rb +18 -0
  357. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_user.rb +18 -0
  358. data/lib/ecoportal/api/graphql/input/workflow_command/remove_scheduled_callback.rb +18 -0
  359. data/lib/ecoportal/api/graphql/input/workflow_command/remove_section.rb +18 -0
  360. data/lib/ecoportal/api/graphql/input/workflow_command/remove_select_field_option.rb +17 -0
  361. data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage.rb +18 -0
  362. data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage_section.rb +18 -0
  363. data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage_tag.rb +18 -0
  364. data/lib/ecoportal/api/graphql/input/workflow_command/remove_strategy.rb +18 -0
  365. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task.rb +18 -0
  366. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_assignment_user_group.rb +18 -0
  367. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_due.rb +18 -0
  368. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_priority_level.rb +18 -0
  369. data/lib/ecoportal/api/graphql/input/workflow_command/reorder_forces.rb +18 -0
  370. data/lib/ecoportal/api/graphql/input/workflow_command/reorder_section.rb +18 -0
  371. data/lib/ecoportal/api/graphql/input/workflow_command.rb +251 -0
  372. data/lib/ecoportal/api/graphql/input.rb +8 -0
  373. data/lib/ecoportal/api/graphql/interface/base_page.rb +100 -58
  374. data/lib/ecoportal/api/graphql/interface/location_structure/nodes.rb +27 -28
  375. data/lib/ecoportal/api/graphql/logic/base_model.rb +2 -0
  376. data/lib/ecoportal/api/graphql/logic/base_query.rb +45 -2
  377. data/lib/ecoportal/api/graphql/logic/input.rb +15 -0
  378. data/lib/ecoportal/api/graphql/model/ai_summary_version.rb +10 -0
  379. data/lib/ecoportal/api/graphql/model/organization.rb +65 -55
  380. data/lib/ecoportal/api/graphql/model/page/basic.rb +14 -0
  381. data/lib/ecoportal/api/graphql/model/page/phased.rb +82 -20
  382. data/lib/ecoportal/api/graphql/model/page.rb +1 -0
  383. data/lib/ecoportal/api/graphql/model/page_union.rb +21 -0
  384. data/lib/ecoportal/api/graphql/model/pages_workflow.rb +20 -0
  385. data/lib/ecoportal/api/graphql/model/preset_view.rb +10 -0
  386. data/lib/ecoportal/api/graphql/model/preview_page.rb +10 -0
  387. data/lib/ecoportal/api/graphql/model/register.rb +10 -0
  388. data/lib/ecoportal/api/graphql/model.rb +8 -0
  389. data/lib/ecoportal/api/graphql/mutation/ai_summary/generate.rb +45 -0
  390. data/lib/ecoportal/api/graphql/mutation/ai_summary/submit_feedback.rb +40 -0
  391. data/lib/ecoportal/api/graphql/mutation/ai_summary.rb +13 -0
  392. data/lib/ecoportal/api/graphql/mutation/kickstand/bulk_update_jobs.rb +43 -0
  393. data/lib/ecoportal/api/graphql/mutation/kickstand/bulk_update_workflows.rb +43 -0
  394. data/lib/ecoportal/api/graphql/mutation/kickstand/fail_job.rb +39 -0
  395. data/lib/ecoportal/api/graphql/mutation/kickstand/fail_workflow.rb +39 -0
  396. data/lib/ecoportal/api/graphql/mutation/kickstand/start_job.rb +39 -0
  397. data/lib/ecoportal/api/graphql/mutation/kickstand/start_workflow.rb +39 -0
  398. data/lib/ecoportal/api/graphql/mutation/kickstand/stop_workflow.rb +39 -0
  399. data/lib/ecoportal/api/graphql/mutation/kickstand.rb +18 -0
  400. data/lib/ecoportal/api/graphql/mutation/location_structure/apply_commands.rb +3 -3
  401. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/add_commands.rb +2 -2
  402. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/create.rb +2 -2
  403. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/drop_bad_commands.rb +3 -3
  404. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/publish.rb +3 -3
  405. data/lib/ecoportal/api/graphql/mutation/page/approve_review_task.rb +40 -0
  406. data/lib/ecoportal/api/graphql/mutation/page/archive.rb +40 -0
  407. data/lib/ecoportal/api/graphql/mutation/page/batch_update_review_task.rb +40 -0
  408. data/lib/ecoportal/api/graphql/mutation/page/build_from_template.rb +50 -0
  409. data/lib/ecoportal/api/graphql/mutation/page/create_draft.rb +40 -0
  410. data/lib/ecoportal/api/graphql/mutation/page/create_from_template.rb +43 -0
  411. data/lib/ecoportal/api/graphql/mutation/page/delete_draft.rb +40 -0
  412. data/lib/ecoportal/api/graphql/mutation/page/execute_force_commands.rb +69 -0
  413. data/lib/ecoportal/api/graphql/mutation/page/execute_workflow_commands.rb +51 -0
  414. data/lib/ecoportal/api/graphql/mutation/page/publish_draft.rb +40 -0
  415. data/lib/ecoportal/api/graphql/mutation/page/reject_review_task.rb +40 -0
  416. data/lib/ecoportal/api/graphql/mutation/page/restart_review_task.rb +40 -0
  417. data/lib/ecoportal/api/graphql/mutation/page/unarchive.rb +40 -0
  418. data/lib/ecoportal/api/graphql/mutation/page/undo_review_task.rb +40 -0
  419. data/lib/ecoportal/api/graphql/mutation/page/update.rb +40 -0
  420. data/lib/ecoportal/api/graphql/mutation/page/update_variable_bindings.rb +44 -0
  421. data/lib/ecoportal/api/graphql/mutation/page.rb +28 -0
  422. data/lib/ecoportal/api/graphql/mutation/preset_view/create.rb +35 -0
  423. data/lib/ecoportal/api/graphql/mutation/preset_view/destroy.rb +35 -0
  424. data/lib/ecoportal/api/graphql/mutation/preset_view/permission.rb +37 -0
  425. data/lib/ecoportal/api/graphql/mutation/preset_view/update.rb +35 -0
  426. data/lib/ecoportal/api/graphql/mutation/preset_view.rb +15 -0
  427. data/lib/ecoportal/api/graphql/mutation/register/create.rb +35 -0
  428. data/lib/ecoportal/api/graphql/mutation/register/destroy.rb +35 -0
  429. data/lib/ecoportal/api/graphql/mutation/register/update.rb +35 -0
  430. data/lib/ecoportal/api/graphql/mutation/register.rb +14 -0
  431. data/lib/ecoportal/api/graphql/mutation/smart_fill/generate.rb +36 -0
  432. data/lib/ecoportal/api/graphql/mutation/smart_fill/submit_feedback.rb +40 -0
  433. data/lib/ecoportal/api/graphql/mutation/smart_fill.rb +13 -0
  434. data/lib/ecoportal/api/graphql/mutation/template/create.rb +39 -0
  435. data/lib/ecoportal/api/graphql/mutation/template/create_related_page.rb +46 -0
  436. data/lib/ecoportal/api/graphql/mutation/template/destroy_related_page.rb +43 -0
  437. data/lib/ecoportal/api/graphql/mutation/template/publish.rb +39 -0
  438. data/lib/ecoportal/api/graphql/mutation/template/unpublish.rb +39 -0
  439. data/lib/ecoportal/api/graphql/mutation/template/update.rb +43 -0
  440. data/lib/ecoportal/api/graphql/mutation/template/update_information.rb +43 -0
  441. data/lib/ecoportal/api/graphql/mutation/template.rb +18 -0
  442. data/lib/ecoportal/api/graphql/mutation.rb +8 -0
  443. data/lib/ecoportal/api/graphql/payload/ai_summary_generate.rb +12 -0
  444. data/lib/ecoportal/api/graphql/payload/execute_workflow_commands.rb +36 -0
  445. data/lib/ecoportal/api/graphql/payload/force_commands.rb +31 -0
  446. data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_jobs.rb +36 -0
  447. data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_workflows.rb +36 -0
  448. data/lib/ecoportal/api/graphql/payload/kickstand/job.rb +13 -0
  449. data/lib/ecoportal/api/graphql/payload/kickstand/workflow.rb +13 -0
  450. data/lib/ecoportal/api/graphql/payload/kickstand.rb +15 -0
  451. data/lib/ecoportal/api/graphql/payload/location_structure/draft/create.rb +33 -34
  452. data/lib/ecoportal/api/graphql/payload/ok_payload.rb +21 -0
  453. data/lib/ecoportal/api/graphql/payload/page/archive.rb +13 -0
  454. data/lib/ecoportal/api/graphql/payload/page/build_from_template.rb +13 -0
  455. data/lib/ecoportal/api/graphql/payload/page/create_from_template.rb +13 -0
  456. data/lib/ecoportal/api/graphql/payload/page/draft.rb +13 -0
  457. data/lib/ecoportal/api/graphql/payload/page/review_task.rb +13 -0
  458. data/lib/ecoportal/api/graphql/payload/page/unarchive.rb +13 -0
  459. data/lib/ecoportal/api/graphql/payload/page/update.rb +13 -0
  460. data/lib/ecoportal/api/graphql/payload/page/update_variable_bindings.rb +13 -0
  461. data/lib/ecoportal/api/graphql/payload/page.rb +19 -0
  462. data/lib/ecoportal/api/graphql/payload/preset_view.rb +11 -0
  463. data/lib/ecoportal/api/graphql/payload/register.rb +11 -0
  464. data/lib/ecoportal/api/graphql/payload/template/create.rb +13 -0
  465. data/lib/ecoportal/api/graphql/payload/template/create_related_page.rb +13 -0
  466. data/lib/ecoportal/api/graphql/payload/template/destroy_related_page.rb +13 -0
  467. data/lib/ecoportal/api/graphql/payload/template/publish.rb +13 -0
  468. data/lib/ecoportal/api/graphql/payload/template/unpublish.rb +13 -0
  469. data/lib/ecoportal/api/graphql/payload/template/update.rb +13 -0
  470. data/lib/ecoportal/api/graphql/payload/template/update_information.rb +13 -0
  471. data/lib/ecoportal/api/graphql/payload/template.rb +18 -0
  472. data/lib/ecoportal/api/graphql/payload.rb +11 -0
  473. data/lib/ecoportal/api/graphql/query/action.rb +1 -1
  474. data/lib/ecoportal/api/graphql/query/action_categories.rb +1 -1
  475. data/lib/ecoportal/api/graphql/query/actions.rb +2 -2
  476. data/lib/ecoportal/api/graphql/query/contractor_entities.rb +1 -1
  477. data/lib/ecoportal/api/graphql/query/file_upload_signature.rb +76 -0
  478. data/lib/ecoportal/api/graphql/query/location_structure/draft.rb +2 -2
  479. data/lib/ecoportal/api/graphql/query/location_structure.rb +1 -1
  480. data/lib/ecoportal/api/graphql/query/location_structures.rb +1 -1
  481. data/lib/ecoportal/api/graphql/query/page.rb +45 -0
  482. data/lib/ecoportal/api/graphql/query/page_delta.rb +47 -0
  483. data/lib/ecoportal/api/graphql/query/page_with_forces.rb +43 -0
  484. data/lib/ecoportal/api/graphql/query/pages.rb +59 -0
  485. data/lib/ecoportal/api/graphql/query/pages_workflow_commands.rb +59 -0
  486. data/lib/ecoportal/api/graphql/query/register_preset_views.rb +78 -0
  487. data/lib/ecoportal/api/graphql/query/register_preview_pages.rb +83 -0
  488. data/lib/ecoportal/api/graphql/query/templates.rb +53 -0
  489. data/lib/ecoportal/api/graphql/query.rb +11 -0
  490. data/lib/ecoportal/api/graphql.rb +60 -2
  491. data/lib/ecoportal/api/graphql_version.rb +5 -5
  492. data/scripts/auto-worker-scheduler.sh +386 -0
  493. data/tests/contractor_entity_create.rb +19 -19
  494. data/tests/contractor_entity_udpate.rb +20 -20
  495. data/tests/dump_page_model.rb +74 -0
  496. data/tests/loc_structure_get.rb +1 -2
  497. data/tests/loc_structure_update.rb +51 -51
  498. data/tests/loc_structures_get.rb +15 -15
  499. metadata +436 -5
@@ -0,0 +1,386 @@
1
+ #!/usr/bin/env bash
2
+ # auto-worker-scheduler.sh
3
+ # Scheduler for auto-todo-worker. Called by the Claude Code Stop hook.
4
+ # Reads local config, checks token budget and conflict guard, then
5
+ # launches the worker as a background process if all gates pass.
6
+ #
7
+ # Log format: TIMESTAMP | ACTION | REASON
8
+ # Log file: .ai-assistance/local/auto-worker-changes.log
9
+ #
10
+ # Usage: bash scripts/auto-worker-scheduler.sh
11
+ # (called automatically by Stop hook — no arguments)
12
+ #
13
+ # Requires: jq (for JSON parsing). Falls back to grep/sed on missing jq.
14
+
15
+ set -euo pipefail
16
+
17
+ # ---------------------------------------------------------------------------
18
+ # Paths (all relative — script must be run from repo root)
19
+ # ---------------------------------------------------------------------------
20
+ TOKEN_BUDGET_JSON=".ai-assistance/token-budget.json"
21
+ LAST_RUN_JSON=".ai-assistance/local/auto-worker-last-run.json"
22
+ SESSION_LOCK=".ai-assistance/local/session.lock"
23
+ CHANGES_LOG=".ai-assistance/local/auto-worker-changes.log"
24
+ STDOUT_LOG=".ai-assistance/local/auto-worker-stdout.log"
25
+ STDERR_LOG=".ai-assistance/local/auto-worker-stderr.log"
26
+ PROMPT_FILE=".ai-assistance/local/auto-worker-prompt.txt"
27
+
28
+ # --dry-run: run every gate and log what WOULD launch, but spawn nothing.
29
+ # Use this to smoke-test the gates without burning tokens on a real worker.
30
+ DRY_RUN=0
31
+ if [ "${1:-}" = "--dry-run" ]; then
32
+ DRY_RUN=1
33
+ fi
34
+
35
+ # ---------------------------------------------------------------------------
36
+ # Helpers
37
+ # ---------------------------------------------------------------------------
38
+
39
+ # ai_log_usage <component> <action> <detail> [session_id]
40
+ # Inline copy — scheduler is self-contained; common.sh is not sourced here.
41
+ # Never fails fatally; all errors suppressed.
42
+ ai_log_usage() {
43
+ local component="${1:-unknown}"
44
+ local action="${2:-run}"
45
+ local detail="${3:-}"
46
+ local session_id="${4:-}"
47
+ local log_dir=".ai-assistance/local/kpi"
48
+ local week
49
+ week=$(date +%Y-W%V 2>/dev/null || echo "unknown")
50
+ local log_file="${log_dir}/usage-${week}.jsonl"
51
+ local ts
52
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || echo "unknown")
53
+ mkdir -p "$log_dir" 2>/dev/null || true
54
+ printf '{"component":"%s","action":"%s","detail":"%s","ts":"%s","session_id":"%s"}\n' \
55
+ "$component" "$action" "$detail" "$ts" "$session_id" >> "$log_file" 2>/dev/null || true
56
+ }
57
+
58
+ log_action() {
59
+ local action="$1"
60
+ local reason="$2"
61
+ local ts
62
+ ts=$(date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date +"%Y-%m-%dT%H:%M:%SZ")
63
+ mkdir -p "$(dirname "$CHANGES_LOG")"
64
+ printf "%s | %s | %s\n" "$ts" "$action" "$reason" >> "$CHANGES_LOG"
65
+ }
66
+
67
+ # Read a JSON field using jq if available, otherwise grep+sed fallback.
68
+ # Usage: json_field <file> <dotted.key> e.g. json_field config.json auto_worker.enabled
69
+ json_field() {
70
+ local file="$1"
71
+ local key="$2"
72
+ if command -v jq >/dev/null 2>&1; then
73
+ jq -r ".${key} // empty" "$file" 2>/dev/null
74
+ else
75
+ # Minimal fallback: grep for the last segment key, extract bare value.
76
+ local leaf
77
+ leaf=$(printf '%s' "$key" | sed 's/.*\.//')
78
+ grep -o "\"${leaf}\"[[:space:]]*:[[:space:]]*[^,}]*" "$file" 2>/dev/null \
79
+ | tail -1 \
80
+ | sed 's/.*:[[:space:]]*//' \
81
+ | tr -d '"' \
82
+ | tr -d ' '
83
+ fi
84
+ }
85
+
86
+ # Make silent failures visible. With `set -e`, any unexpected non-zero exit
87
+ # fires this trap and records an ERROR line before the script dies. The Stop
88
+ # hook swallows stderr (`2>/dev/null || true`), so without this an early
89
+ # failure (missing jq/python, malformed JSON, etc.) would leave no trace at
90
+ # all — which is exactly how this script went dark without anyone noticing.
91
+ trap 'rc=$?; log_action "ERROR" "scheduler aborted at line ${LINENO} (rc=${rc})"' ERR
92
+
93
+ # ---------------------------------------------------------------------------
94
+ # Gate 1: auto_worker.enabled
95
+ # ---------------------------------------------------------------------------
96
+
97
+ if [ ! -f "$TOKEN_BUDGET_JSON" ]; then
98
+ log_action "SKIP" "token-budget.json not found — auto_worker not configured"
99
+ ai_log_usage "script/auto-worker-scheduler" "skip" "auto_worker not enabled -- token-budget.json not found"
100
+ exit 0
101
+ fi
102
+
103
+ enabled=$(json_field "$TOKEN_BUDGET_JSON" "auto_worker.enabled")
104
+ if [ "$enabled" != "true" ]; then
105
+ log_action "SKIP" "auto_worker.enabled is false or absent in token-budget.json"
106
+ ai_log_usage "script/auto-worker-scheduler" "skip" "auto_worker not enabled"
107
+ exit 0
108
+ fi
109
+
110
+ # ---------------------------------------------------------------------------
111
+ # Gate 1b: Eligible work must exist — at least one [auto] / [auto:last] item
112
+ # ---------------------------------------------------------------------------
113
+ # Without this gate, every trigger spins up a full `claude --print` worker even
114
+ # when TODO.md has zero tagged items — the worker then no-ops, burning a launch
115
+ # (and tokens) for nothing. This was the pattern behind the 42 historical
116
+ # launches that completed no work, and it is also why a repo with no TODO.md at
117
+ # all (e.g. a fresh sibling) must SKIP rather than launch into an error.
118
+ # The tag set is the eligibility boundary defined in
119
+ # standards/tooling/auto-worker-eligibility.md.
120
+ # NOTE: \[auto\] does NOT match [auto:last] — the regex MUST be \[auto(:last)?\].
121
+ TODO_FILE="TODO.md"
122
+ if [ ! -f "$TODO_FILE" ]; then
123
+ log_action "SKIP" "No TODO.md in repo root — no eligible work to schedule"
124
+ ai_log_usage "script/auto-worker-scheduler" "skip" "no TODO.md present"
125
+ exit 0
126
+ fi
127
+ if ! grep -qE '\[auto(:last)?\]' "$TODO_FILE"; then
128
+ log_action "SKIP" "No eligible work — no [auto] or [auto:last] items in TODO.md"
129
+ ai_log_usage "script/auto-worker-scheduler" "skip" "no [auto]/[auto:last] items in TODO.md"
130
+ exit 0
131
+ fi
132
+
133
+ # ---------------------------------------------------------------------------
134
+ # Gate 2: Conflict guard — check for active Claude session via session.lock
135
+ # ---------------------------------------------------------------------------
136
+
137
+ if [ -f "$SESSION_LOCK" ]; then
138
+ lock_content=""
139
+ if [ -r "$SESSION_LOCK" ]; then
140
+ lock_content=$(cat "$SESSION_LOCK" 2>/dev/null || true)
141
+ fi
142
+ log_action "SKIP" "Active Claude session detected (session.lock present: ${lock_content})"
143
+ ai_log_usage "script/auto-worker-scheduler" "skip" "session.lock present"
144
+ exit 0
145
+ fi
146
+
147
+ # ---------------------------------------------------------------------------
148
+ # Gate 3: Token budget threshold check
149
+ # ---------------------------------------------------------------------------
150
+ # Find the current ISO week KPI file. Format: weekly-YYYY-WNN.json
151
+ # We compute ISO week ourselves for portability.
152
+
153
+ iso_week() {
154
+ # Returns YYYY-WNN string for today (ISO 8601 week numbering)
155
+ if command -v python3 >/dev/null 2>&1; then
156
+ python3 -c "
157
+ import datetime
158
+ today = datetime.date.today()
159
+ iso = today.isocalendar()
160
+ print('%04d-W%02d' % (iso[0], iso[1]))
161
+ "
162
+ elif command -v python >/dev/null 2>&1; then
163
+ python -c "
164
+ import datetime
165
+ today = datetime.date.today()
166
+ iso = today.isocalendar()
167
+ print('%04d-W%02d' % (iso[0], iso[1]))
168
+ "
169
+ else
170
+ # Fallback: use date command Week-of-year (not strictly ISO but close enough)
171
+ date +"%Y-W%V" 2>/dev/null || date +"%Y-W%U"
172
+ fi
173
+ }
174
+
175
+ KPI_DIR=".ai-assistance/local/kpi"
176
+ WEEK_KEY=$(iso_week)
177
+ KPI_FILE="${KPI_DIR}/weekly-${WEEK_KEY}.json"
178
+
179
+ # Read quota and usage from KPI file (if present)
180
+ weekly_tokens_used=0
181
+ weekly_quota=0
182
+ window_start_ts="" # ISO timestamp of first session start in current 5-hour window
183
+
184
+ if [ -f "$KPI_FILE" ] && command -v jq >/dev/null 2>&1; then
185
+ # Sum tokens_used across all sessions
186
+ weekly_tokens_used=$(jq '[.sessions[]?.tokens_used // 0] | add // 0' "$KPI_FILE" 2>/dev/null || echo "0")
187
+ weekly_quota=$(jq -r '.quota // 0' "$KPI_FILE" 2>/dev/null || echo "0")
188
+
189
+ # Find most recent session start to compute reset window
190
+ window_start_ts=$(jq -r '
191
+ [.sessions[]?.session_start // empty] | sort | last // empty
192
+ ' "$KPI_FILE" 2>/dev/null || true)
193
+ fi
194
+
195
+ # Read quota from token-budget.json as fallback
196
+ if [ "$weekly_quota" = "0" ] || [ -z "$weekly_quota" ]; then
197
+ quota_from_config=$(json_field "$TOKEN_BUDGET_JSON" "weekly_quota.total_tokens")
198
+ if [ "$quota_from_config" != "null" ] && [ -n "$quota_from_config" ]; then
199
+ weekly_quota="$quota_from_config"
200
+ fi
201
+ fi
202
+
203
+ # If no quota is set (null), skip the threshold gate entirely
204
+ if [ "$weekly_quota" = "0" ] || [ "$weekly_quota" = "null" ] || [ -z "$weekly_quota" ]; then
205
+ log_action "OK" "No weekly quota set — skipping token threshold gate"
206
+ else
207
+ # Calculate usage percentage
208
+ if command -v python3 >/dev/null 2>&1; then
209
+ usage_pct=$(python3 -c "
210
+ used = float('${weekly_tokens_used}' or '0')
211
+ quota = float('${weekly_quota}')
212
+ print('%.1f' % (used / quota * 100) if quota > 0 else '0')
213
+ ")
214
+ else
215
+ usage_pct=0
216
+ fi
217
+
218
+ # Determine time remaining in current 5-hour reset window
219
+ # 5-hour window = 18000 seconds
220
+ window_seconds_elapsed=0
221
+ if [ -n "$window_start_ts" ] && command -v python3 >/dev/null 2>&1; then
222
+ window_seconds_elapsed=$(python3 -c "
223
+ import datetime, sys
224
+ try:
225
+ ts = '${window_start_ts}'.replace('Z', '+00:00')
226
+ start = datetime.datetime.fromisoformat(ts)
227
+ now = datetime.datetime.now(datetime.timezone.utc)
228
+ elapsed = (now - start).total_seconds()
229
+ print(int(max(0, elapsed)))
230
+ except Exception:
231
+ print(0)
232
+ ")
233
+ fi
234
+
235
+ WINDOW_DURATION=18000 # 5 hours in seconds
236
+ window_remaining=$(( WINDOW_DURATION - window_seconds_elapsed ))
237
+ if [ "$window_remaining" -lt 0 ]; then
238
+ window_remaining=0
239
+ fi
240
+ window_remaining_min=$(( window_remaining / 60 ))
241
+
242
+ # Determine threshold based on time remaining in window (ADR-007 table)
243
+ # >120 min -> 65%; 60-120 -> 75%; 45-60 -> 80%; 30-45 -> 90%; 15-30 -> 95%; <15 -> skip
244
+ if [ "$window_remaining_min" -lt 15 ]; then
245
+ log_action "SKIP" "Less than 15 min remaining in token reset window — will not launch"
246
+ ai_log_usage "script/auto-worker-scheduler" "skip" "token budget -- less than 15 min remaining in reset window"
247
+ exit 0
248
+ elif [ "$window_remaining_min" -lt 30 ]; then
249
+ threshold=95
250
+ elif [ "$window_remaining_min" -lt 45 ]; then
251
+ threshold=90
252
+ elif [ "$window_remaining_min" -lt 60 ]; then
253
+ threshold=80
254
+ elif [ "$window_remaining_min" -lt 120 ]; then
255
+ threshold=75
256
+ else
257
+ threshold=65
258
+ fi
259
+
260
+ # Compare usage_pct against threshold (integer comparison via python3)
261
+ if command -v python3 >/dev/null 2>&1; then
262
+ over_threshold=$(python3 -c "
263
+ pct = float('${usage_pct}' or '0')
264
+ thr = float('${threshold}')
265
+ print('true' if pct >= thr else 'false')
266
+ ")
267
+ else
268
+ over_threshold="false"
269
+ fi
270
+
271
+ if [ "$over_threshold" = "true" ]; then
272
+ log_action "SKIP" "Token usage ${usage_pct}% >= threshold ${threshold}% (${window_remaining_min} min remaining in window)"
273
+ ai_log_usage "script/auto-worker-scheduler" "skip" "token budget at ${usage_pct}% (threshold ${threshold}%)"
274
+ exit 0
275
+ fi
276
+
277
+ log_action "OK" "Token gate passed: ${usage_pct}% used, threshold ${threshold}% (${window_remaining_min} min remaining)"
278
+ fi
279
+
280
+ # ---------------------------------------------------------------------------
281
+ # Gate 4: Determine cadence (informational — actual cron cadence managed by
282
+ # CronCreate; this script just logs the recommendation)
283
+ # ---------------------------------------------------------------------------
284
+
285
+ recommended_cadence="2hr"
286
+ if [ -f "$LAST_RUN_JSON" ] && command -v jq >/dev/null 2>&1; then
287
+ completed_count=$(jq '.completed | length' "$LAST_RUN_JSON" 2>/dev/null || echo "0")
288
+ if [ "$completed_count" -gt "0" ]; then
289
+ recommended_cadence="30min"
290
+ fi
291
+ fi
292
+
293
+ # ---------------------------------------------------------------------------
294
+ # Gate 5: dangerously_skip_permissions is REQUIRED
295
+ # ---------------------------------------------------------------------------
296
+ # A headless `claude --print` worker has no way to answer interactive
297
+ # permission prompts — without skip-permissions it stalls indefinitely and
298
+ # does no work. Require explicit opt-in rather than launching a worker that
299
+ # can only hang.
300
+
301
+ skip_perms=$(json_field "$TOKEN_BUDGET_JSON" "auto_worker.dangerously_skip_permissions")
302
+ if [ "$skip_perms" != "true" ]; then
303
+ log_action "SKIP" "auto_worker.dangerously_skip_permissions is not true — a headless (--print) worker cannot answer permission prompts and would stall. Set it to true in token-budget.json to enable."
304
+ ai_log_usage "script/auto-worker-scheduler" "skip" "dangerously_skip_permissions not enabled -- headless worker requires it"
305
+ exit 0
306
+ fi
307
+
308
+ AUTO_WORKER_PROMPT="Run the auto-worker for this repo.
309
+
310
+ Instructions:
311
+ 1. Read TODO.md and collect all items tagged \`[auto]\` or \`[auto:last]\`.
312
+ 2. If no \`[auto]\` items exist, exit cleanly with a brief log entry.
313
+ 3. Plan execution order as a dependency graph — do NOT follow TODO list order.
314
+ - Items without dependencies on each other may run in parallel (branch out when the work is self-contained enough to isolate).
315
+ - \`[auto:last]\` items run only after all \`[auto]\` items complete or are skipped.
316
+ 4. For each item:
317
+ - Execute the task.
318
+ - Mark it \`[x]\` in TODO.md on completion.
319
+ - Add any discovered follow-up tasks as new TODO items; tag \`[auto]\` only if they meet the eligibility criteria in standards/tooling/auto-worker-eligibility.md.
320
+ 5. Do NOT touch items that are not tagged \`[auto]\` or \`[auto:last]\`.
321
+ 6. At the end, write a one-paragraph summary of what was done, skipped, and added to TODO."
322
+
323
+ # Write the prompt to a file and feed it to claude via stdin. This avoids the
324
+ # quoting/newline hazards of passing a multi-line prompt as a CLI argument —
325
+ # the previous Windows path crammed the whole prompt (newlines, quotes,
326
+ # backticks) into a single PowerShell -ArgumentList string, which produced a
327
+ # broken command that launched nothing while still logging "LAUNCHED".
328
+ mkdir -p "$(dirname "$PROMPT_FILE")"
329
+ printf '%s\n' "$AUTO_WORKER_PROMPT" > "$PROMPT_FILE"
330
+
331
+ # ---------------------------------------------------------------------------
332
+ # Dry run: log what would happen, spawn nothing.
333
+ # ---------------------------------------------------------------------------
334
+ if [ "$DRY_RUN" = "1" ]; then
335
+ log_action "DRY-RUN" "All gates passed. Would launch: claude --dangerously-skip-permissions --print < ${PROMPT_FILE} > ${STDOUT_LOG} (cadence recommendation: ${recommended_cadence})"
336
+ ai_log_usage "script/auto-worker-scheduler" "dry-run" "all gates passed -- would launch auto-todo-worker"
337
+ exit 0
338
+ fi
339
+
340
+ # ---------------------------------------------------------------------------
341
+ # Launch: run auto-todo-worker as a detached background process.
342
+ # Output is ALWAYS redirected to STDOUT_LOG/STDERR_LOG so a failed or empty
343
+ # run leaves a trace (the previous Windows path captured nothing).
344
+ # ---------------------------------------------------------------------------
345
+
346
+ log_action "LAUNCH" "Launching auto-todo-worker (cadence recommendation: ${recommended_cadence})"
347
+ ai_log_usage "script/auto-worker-scheduler" "launch" "launching auto-todo-worker"
348
+
349
+ launch_pid=""
350
+ if [[ "${OSTYPE:-}" == "msys" ]] || [[ "${OSTYPE:-}" == "cygwin" ]] || \
351
+ [[ "${OS:-}" == "Windows_NT" ]]; then
352
+ # Windows via Git Bash. Start-Process detaches the worker from this hook's
353
+ # shell so it outlives the Stop hook. -RedirectStandardInput feeds the
354
+ # prompt file (no fragile arg quoting); -RedirectStandardOutput/Error
355
+ # capture the run; -PassThru returns the REAL worker PID (the old code
356
+ # logged the wrapper job's PID via `$!`, which was meaningless).
357
+ # Note: stdout and stderr MUST be different files — Start-Process rejects
358
+ # redirecting both to the same path.
359
+ abs_prompt="$(cygpath -w "$PROMPT_FILE" 2>/dev/null || printf '%s' "${PWD}/${PROMPT_FILE}")"
360
+ abs_stdout="$(cygpath -w "$STDOUT_LOG" 2>/dev/null || printf '%s' "${PWD}/${STDOUT_LOG}")"
361
+ abs_stderr="$(cygpath -w "$STDERR_LOG" 2>/dev/null || printf '%s' "${PWD}/${STDERR_LOG}")"
362
+ abs_cwd="$(cygpath -w "$PWD" 2>/dev/null || printf '%s' "${PWD}")"
363
+ launch_pid=$(powershell -NoProfile -Command "
364
+ \$p = Start-Process -FilePath 'claude' \
365
+ -ArgumentList '--dangerously-skip-permissions','--print' \
366
+ -RedirectStandardInput '${abs_prompt}' \
367
+ -RedirectStandardOutput '${abs_stdout}' \
368
+ -RedirectStandardError '${abs_stderr}' \
369
+ -WorkingDirectory '${abs_cwd}' \
370
+ -NoNewWindow -PassThru
371
+ \$p.Id" 2>/dev/null | tr -d '[:space:]') || true
372
+ else
373
+ # Unix / macOS / WSL2: feed prompt via stdin, capture output, detach.
374
+ nohup claude --dangerously-skip-permissions --print \
375
+ < "$PROMPT_FILE" > "$STDOUT_LOG" 2>&1 &
376
+ launch_pid=$!
377
+ fi
378
+
379
+ if [ -n "${launch_pid:-}" ]; then
380
+ log_action "LAUNCHED" "Background worker PID ${launch_pid} — output -> ${STDOUT_LOG}"
381
+ ai_log_usage "script/auto-worker-scheduler" "launched" "worker PID ${launch_pid}"
382
+ else
383
+ log_action "ERROR" "Launch returned no PID — worker likely failed to start. Check ${STDERR_LOG}."
384
+ ai_log_usage "script/auto-worker-scheduler" "error" "launch returned no PID"
385
+ fi
386
+ exit 0
@@ -1,19 +1,19 @@
1
- require_relative 'local_libs'
2
-
3
- api = Ecoportal::API::GraphQL.new
4
- response = api.createContractorEntity(input: {
5
- name: "Caras Galathon",
6
- active: true,
7
- approved: true,
8
- associatedPeopleIds: [
9
- "5adfbef76fb80400047535b3"
10
- ],
11
- leadContractorIds: [
12
- "5adfbef76fb80400047535b3"
13
- ],
14
- clientMutationId: ""
15
- })
16
-
17
- if response.success? && entity = response.item
18
- puts "Created contractor entity '#{entity.name}' (approved? #{entity.approved})"
19
- end
1
+ require_relative 'local_libs'
2
+
3
+ api = Ecoportal::API::GraphQL.new
4
+ response = api.createContractorEntity(input: {
5
+ name: "Caras Galathon",
6
+ active: true,
7
+ approved: true,
8
+ associatedPeopleIds: [
9
+ "5adfbef76fb80400047535b3"
10
+ ],
11
+ leadContractorIds: [
12
+ "5adfbef76fb80400047535b3"
13
+ ],
14
+ clientMutationId: ""
15
+ })
16
+
17
+ if response.success? && (entity = response.item)
18
+ puts "Created contractor entity '#{entity.name}' (approved? #{entity.approved})"
19
+ end
@@ -1,20 +1,20 @@
1
- require_relative 'local_libs'
2
-
3
- api = Ecoportal::API::GraphQL.new
4
- response = api.contractorEntity.update(input: {
5
- id: "62b04d83fa9170001d3d303f",
6
- name: "Caras Galathon",
7
- active: true,
8
- approved: true,
9
- # associatedPeopleIds: [
10
- # "5adfbef76fb80400047535b3"
11
- # ],
12
- leadContractorIds: {
13
- additions: ["5adfbef76fb80400047535b3"]
14
- },
15
- clientMutationId: ""
16
- })
17
-
18
- if response.success? && entity = response.item
19
- puts "Updated contractor entity '#{entity.name}' (approved? #{entity.approved})"
20
- end
1
+ require_relative 'local_libs'
2
+
3
+ api = Ecoportal::API::GraphQL.new
4
+ response = api.contractorEntity.update(input: {
5
+ id: "62b04d83fa9170001d3d303f",
6
+ name: "Caras Galathon",
7
+ active: true,
8
+ approved: true,
9
+ # associatedPeopleIds: [
10
+ # "5adfbef76fb80400047535b3"
11
+ # ],
12
+ leadContractorIds: {
13
+ additions: ["5adfbef76fb80400047535b3"]
14
+ },
15
+ clientMutationId: ""
16
+ })
17
+
18
+ if response.success? && (entity = response.item)
19
+ puts "Updated contractor entity '#{entity.name}' (approved? #{entity.approved})"
20
+ end
@@ -0,0 +1,74 @@
1
+ require_relative 'local_libs'
2
+ require 'json'
3
+ require 'fileutils'
4
+
5
+ # Dump a page's GraphQL model (the raw CommonPageUnion doc) to a JSON file, so a real page
6
+ # can be captured as a spec fixture / stub. Run it BEFORE and AFTER a submit/sign_off (or any
7
+ # mutation) to capture both states and diff them — the dumps double as regression fixtures.
8
+ #
9
+ # Usage (run in an env where the GraphQL connection is configured, like the other tests/):
10
+ # ruby tests/dump_page_model.rb <PAGE_ID> [--out PATH] [--stage NAME_OR_ID] [--label before|after]
11
+ #
12
+ # Examples:
13
+ # # capture the TOOCS page before submitting
14
+ # ruby tests/dump_page_model.rb 6a3225532b97b00073c23aa8 --label before
15
+ # # ...run the case live (or a manual updatePage)...
16
+ # # capture it after
17
+ # ruby tests/dump_page_model.rb 6a3225532b97b00073c23aa8 --label after
18
+ # # then diff the two JSON files to see exactly what the submit changed.
19
+ #
20
+ # Default output path: spec/fixtures/pages/<page_id>[_<label>].json
21
+ #
22
+ # A --stage NAME_OR_ID also prints the StageView's stage id (the value that becomes stageId on
23
+ # a submit) so you can confirm the right stage was resolved.
24
+
25
+ def parse_args(argv)
26
+ opts = { page_id: nil, out: nil, stage: nil, label: nil }
27
+ rest = argv.dup
28
+ opts[:page_id] = rest.shift
29
+ until rest.empty?
30
+ flag = rest.shift
31
+ case flag
32
+ when '--out' then opts[:out] = rest.shift
33
+ when '--stage' then opts[:stage] = rest.shift
34
+ when '--label' then opts[:label] = rest.shift
35
+ else
36
+ warn "Unknown argument: #{flag}"
37
+ end
38
+ end
39
+ opts
40
+ end
41
+
42
+ opts = parse_args(ARGV)
43
+
44
+ unless opts[:page_id]
45
+ warn 'Usage: ruby tests/dump_page_model.rb <PAGE_ID> [--out PATH] [--stage NAME_OR_ID] [--label before|after]'
46
+ exit 1
47
+ end
48
+
49
+ default_dir = File.expand_path('../spec/fixtures/pages', __dir__)
50
+ default_name = "#{[opts[:page_id], opts[:label]].compact.join('_')}.json"
51
+ out_path = opts[:out] || File.join(default_dir, default_name)
52
+
53
+ api = Ecoportal::API::GraphQL.new
54
+ page = api.pages.get(opts[:page_id], stage_id: opts[:stage])
55
+
56
+ if page.nil?
57
+ warn "Could not fetch page '#{opts[:page_id]}'"
58
+ exit 2
59
+ end
60
+
61
+ # StageView delegates #doc to the underlying full page; dump the full page doc either way.
62
+ doc = page.respond_to?(:doc) ? page.doc : page.instance_variable_get(:@page)&.doc
63
+
64
+ FileUtils.mkdir_p(File.dirname(out_path))
65
+ File.write(out_path, JSON.pretty_generate(doc))
66
+
67
+ puts "Dumped page '#{opts[:page_id]}' → #{out_path}"
68
+ puts " name: #{page.respond_to?(:name) ? page.name : '(n/a)'}"
69
+ puts " patchVer: #{page.respond_to?(:patchVer) ? page.patchVer : '(n/a)'}"
70
+ if opts[:stage]
71
+ resolved = page.respond_to?(:current_stage_id) ? page.current_stage_id : nil
72
+ puts " stage '#{opts[:stage]}' → stageId that a submit would target: #{resolved.inspect}"
73
+ end
74
+ puts 'Tip: capture --label before and --label after a submit, then diff the two JSON files.'
@@ -1,9 +1,8 @@
1
1
  require_relative 'local_libs'
2
2
 
3
- STRUCT_ID = "592642a4ae0c6a00236b110d" # mini test
3
+ STRUCT_ID = "592642a4ae0c6a00236b110d".freeze # mini test
4
4
  # STRUCT_ID = "626745bcba616a001f7e5011" # wcc
5
5
 
6
-
7
6
  api = Ecoportal::API::GraphQL.new
8
7
  api.currentOrganization.locationStructure(id: STRUCT_ID).tap do |tree|
9
8
  puts "'#{tree.name}' Structure (#{tree.id})"
@@ -1,51 +1,51 @@
1
- require_relative 'local_libs'
2
-
3
- STRUCT_ID = "592642a4ae0c6a00236b110d" # mini test
4
- # STRUCT_ID = "626745bcba616a001f7e5011" # wcc
5
-
6
- api = Ecoportal::API::GraphQL.new
7
-
8
- # DESIRED DESIGN: (to review: it might be that draft tree model already stores the commands?)
9
- # tree = api.currentOrganization.LocationStructure(id: STRUCT_ID)
10
- # node = tree.node["SYDNEY"]
11
- # node.name = "Sydney City"
12
- # tree.node["UPS"].move("AUCKLAND") # or tree.move("UPS", to: "AUCKLAND")
13
- # tree.node["FFFF."].delete
14
- # tree.node["UPS"].insert("CHILD", name: "Child").insert("GRAND CHILD", name: "Grand Child")
15
- # tree.change_commands # => return Ecoportal::API::GraphQL::Input::ApplyCommands
16
-
17
- INPUT = {
18
- change: {
19
- clientMutationId: "",
20
- id: STRUCT_ID,
21
- commands: [
22
- { update: { nodeId: "SYDNEY", name: "Sydney City" } },
23
- { move: { nodeId: "UPS", parentId: "AUCKLAND" } },
24
- { archive: { nodeId: "FFFF." } },
25
- { insert: { parentId: "UPS", nodeId: "CHILD", name: "Child" } },
26
- { insert: { parentId: "CHILD", nodeId: "GRAND CHILD", name: "Grand Child" } }
27
- ]
28
- },
29
- revert: {
30
- clientMutationId: "",
31
- id: STRUCT_ID,
32
- commands: [
33
- { update: { nodeId: "SYDNEY", name: "Sydney" } },
34
- { move: { nodeId: "UPS", parentId: "SUB'TAGs" } },
35
- { unarchive: { nodeId: "FFFF." } },
36
- { archive: { nodeId: "CHILD" } }
37
- ]
38
- }
39
- }
40
-
41
- operation = :change
42
- response = api.locationStructure.applyCommands(input: INPUT[operation])
43
-
44
- if response.success? && structure = response.structure
45
- puts "Applied '#{operation}' changes to '#{structure.name}' structure:"
46
- pp structure.treeify
47
- end
48
-
49
- puts "Some more feedback:"
50
- #pp response.results.as_json
51
- pp response.results.map(&:as_json)
1
+ require_relative 'local_libs'
2
+
3
+ STRUCT_ID = "592642a4ae0c6a00236b110d".freeze # mini test
4
+ # STRUCT_ID = "626745bcba616a001f7e5011" # wcc
5
+
6
+ api = Ecoportal::API::GraphQL.new
7
+
8
+ # DESIRED DESIGN: (to review: it might be that draft tree model already stores the commands?)
9
+ # tree = api.currentOrganization.LocationStructure(id: STRUCT_ID)
10
+ # node = tree.node["SYDNEY"]
11
+ # node.name = "Sydney City"
12
+ # tree.node["UPS"].move("AUCKLAND") # or tree.move("UPS", to: "AUCKLAND")
13
+ # tree.node["FFFF."].delete
14
+ # tree.node["UPS"].insert("CHILD", name: "Child").insert("GRAND CHILD", name: "Grand Child")
15
+ # tree.change_commands # => return Ecoportal::API::GraphQL::Input::ApplyCommands
16
+
17
+ INPUT = {
18
+ change: {
19
+ clientMutationId: "",
20
+ id: STRUCT_ID,
21
+ commands: [
22
+ { update: { nodeId: "SYDNEY", name: "Sydney City" } },
23
+ { move: { nodeId: "UPS", parentId: "AUCKLAND" } },
24
+ { archive: { nodeId: "FFFF." } },
25
+ { insert: { parentId: "UPS", nodeId: "CHILD", name: "Child" } },
26
+ { insert: { parentId: "CHILD", nodeId: "GRAND CHILD", name: "Grand Child" } }
27
+ ]
28
+ },
29
+ revert: {
30
+ clientMutationId: "",
31
+ id: STRUCT_ID,
32
+ commands: [
33
+ { update: { nodeId: "SYDNEY", name: "Sydney" } },
34
+ { move: { nodeId: "UPS", parentId: "SUB'TAGs" } },
35
+ { unarchive: { nodeId: "FFFF." } },
36
+ { archive: { nodeId: "CHILD" } }
37
+ ]
38
+ }
39
+ }.freeze
40
+
41
+ operation = :change
42
+ response = api.locationStructure.applyCommands(input: INPUT[operation])
43
+
44
+ if response.success? && (structure = response.structure)
45
+ puts "Applied '#{operation}' changes to '#{structure.name}' structure:"
46
+ pp structure.treeify
47
+ end
48
+
49
+ puts "Some more feedback:"
50
+ #pp response.results.as_json
51
+ pp response.results.map(&:as_json)