@aopslab/aops-server 0.1.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 (185) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +6 -0
  3. package/README.md +21 -0
  4. package/aops-server-runtime.json +11 -0
  5. package/build/client/_app/immutable/chunks/2_TffmqH.js +1 -0
  6. package/build/client/_app/immutable/chunks/3DOfIKW0.js +1 -0
  7. package/build/client/_app/immutable/chunks/B2EkC-sy.js +1 -0
  8. package/build/client/_app/immutable/chunks/CMkIcmi1.js +2 -0
  9. package/build/client/_app/immutable/chunks/rqnVXeyB.js +1 -0
  10. package/build/client/_app/immutable/chunks/sZYZbj9W.js +1 -0
  11. package/build/client/_app/immutable/chunks/wbPk3Yxo.js +81 -0
  12. package/build/client/_app/immutable/entry/app.C7STLTX8.js +2 -0
  13. package/build/client/_app/immutable/entry/start.BC94hOaC.js +1 -0
  14. package/build/client/_app/immutable/nodes/0.BYBfjxZ5.js +1 -0
  15. package/build/client/_app/immutable/nodes/1.BNXFXajG.js +1 -0
  16. package/build/client/_app/version.json +1 -0
  17. package/build/env.js +70 -0
  18. package/build/env.js.map +1 -0
  19. package/build/handler.js +16 -0
  20. package/build/handler.js.map +1 -0
  21. package/build/index.js +139 -0
  22. package/build/index.js.map +1 -0
  23. package/build/server/chunks/0-RfB6m2nq.js +7 -0
  24. package/build/server/chunks/0-RfB6m2nq.js.map +1 -0
  25. package/build/server/chunks/1-_gg8Q0UT.js +9 -0
  26. package/build/server/chunks/1-_gg8Q0UT.js.map +1 -0
  27. package/build/server/chunks/_server.ts-6276EQIF.js +44 -0
  28. package/build/server/chunks/_server.ts-6276EQIF.js.map +1 -0
  29. package/build/server/chunks/_server.ts-B59WFQzX.js +174 -0
  30. package/build/server/chunks/_server.ts-B59WFQzX.js.map +1 -0
  31. package/build/server/chunks/_server.ts-BauJsLZI.js +40 -0
  32. package/build/server/chunks/_server.ts-BauJsLZI.js.map +1 -0
  33. package/build/server/chunks/_server.ts-BnGzJw2-.js +81 -0
  34. package/build/server/chunks/_server.ts-BnGzJw2-.js.map +1 -0
  35. package/build/server/chunks/_server.ts-CP7qM24V.js +34 -0
  36. package/build/server/chunks/_server.ts-CP7qM24V.js.map +1 -0
  37. package/build/server/chunks/_server.ts-Cbq_u99d.js +9 -0
  38. package/build/server/chunks/_server.ts-Cbq_u99d.js.map +1 -0
  39. package/build/server/chunks/_server.ts-Ch8fPT-o.js +92 -0
  40. package/build/server/chunks/_server.ts-Ch8fPT-o.js.map +1 -0
  41. package/build/server/chunks/_server.ts-Cv-yaXZI.js +7 -0
  42. package/build/server/chunks/_server.ts-Cv-yaXZI.js.map +1 -0
  43. package/build/server/chunks/_server.ts-D6lBwOON.js +34 -0
  44. package/build/server/chunks/_server.ts-D6lBwOON.js.map +1 -0
  45. package/build/server/chunks/_server.ts-D84K3pp9.js +11 -0
  46. package/build/server/chunks/_server.ts-D84K3pp9.js.map +1 -0
  47. package/build/server/chunks/_server.ts-DNzU1ToA.js +277 -0
  48. package/build/server/chunks/_server.ts-DNzU1ToA.js.map +1 -0
  49. package/build/server/chunks/_server.ts-DQQnw77t.js +17 -0
  50. package/build/server/chunks/_server.ts-DQQnw77t.js.map +1 -0
  51. package/build/server/chunks/_server.ts-DSxr5l15.js +18 -0
  52. package/build/server/chunks/_server.ts-DSxr5l15.js.map +1 -0
  53. package/build/server/chunks/_server.ts-DZYokvuR.js +80 -0
  54. package/build/server/chunks/_server.ts-DZYokvuR.js.map +1 -0
  55. package/build/server/chunks/_server.ts-Dcqwpz2t.js +144 -0
  56. package/build/server/chunks/_server.ts-Dcqwpz2t.js.map +1 -0
  57. package/build/server/chunks/_server.ts-Di9VJnF4.js +81 -0
  58. package/build/server/chunks/_server.ts-Di9VJnF4.js.map +1 -0
  59. package/build/server/chunks/_server.ts-FBEHFT8b.js +33 -0
  60. package/build/server/chunks/_server.ts-FBEHFT8b.js.map +1 -0
  61. package/build/server/chunks/_server.ts-gZytCuiJ.js +10 -0
  62. package/build/server/chunks/_server.ts-gZytCuiJ.js.map +1 -0
  63. package/build/server/chunks/_server.ts-tNULLyEO.js +261 -0
  64. package/build/server/chunks/_server.ts-tNULLyEO.js.map +1 -0
  65. package/build/server/chunks/agent-gateway-runtime-DTZ4SxaC.js +2598 -0
  66. package/build/server/chunks/agent-gateway-runtime-DTZ4SxaC.js.map +1 -0
  67. package/build/server/chunks/aops-runtime-config-wpVmg7T-.js +179 -0
  68. package/build/server/chunks/aops-runtime-config-wpVmg7T-.js.map +1 -0
  69. package/build/server/chunks/discovery-D9JnSgfu.js +894 -0
  70. package/build/server/chunks/discovery-D9JnSgfu.js.map +1 -0
  71. package/build/server/chunks/error.svelte-DgUOqi-L.js +45 -0
  72. package/build/server/chunks/error.svelte-DgUOqi-L.js.map +1 -0
  73. package/build/server/chunks/handler-BN3-p5rP.js +1733 -0
  74. package/build/server/chunks/handler-BN3-p5rP.js.map +1 -0
  75. package/build/server/chunks/hooks.server-C4wxiH5m.js +52 -0
  76. package/build/server/chunks/hooks.server-C4wxiH5m.js.map +1 -0
  77. package/build/server/chunks/index.js-nbqdVuWC.js +10698 -0
  78. package/build/server/chunks/index.js-nbqdVuWC.js.map +1 -0
  79. package/build/server/chunks/manifest.js-_Re-Wj-y.js +167 -0
  80. package/build/server/chunks/manifest.js-_Re-Wj-y.js.map +1 -0
  81. package/build/server/chunks/plugin-error-normalize-Bq14Qbz3.js +297 -0
  82. package/build/server/chunks/plugin-error-normalize-Bq14Qbz3.js.map +1 -0
  83. package/build/server/chunks/project-alias-DqE2v58Q.js +29 -0
  84. package/build/server/chunks/project-alias-DqE2v58Q.js.map +1 -0
  85. package/build/server/chunks/registry-5amIZito.js +289 -0
  86. package/build/server/chunks/registry-5amIZito.js.map +1 -0
  87. package/build/server/chunks/request-base-url-BDdrsaga.js +24 -0
  88. package/build/server/chunks/request-base-url-BDdrsaga.js.map +1 -0
  89. package/build/server/chunks/request-context-tNeFQjgb.js +422 -0
  90. package/build/server/chunks/request-context-tNeFQjgb.js.map +1 -0
  91. package/build/server/chunks/xf-result-BRDjvftr.js +17 -0
  92. package/build/server/chunks/xf-result-BRDjvftr.js.map +1 -0
  93. package/build/shims.js +33 -0
  94. package/build/shims.js.map +1 -0
  95. package/cockpit/.vite/manifest.json +198 -0
  96. package/cockpit/assets/dm-sans-latin-400-normal-BwCSEQnW.woff +0 -0
  97. package/cockpit/assets/dm-sans-latin-400-normal-CW0RaeGs.woff2 +0 -0
  98. package/cockpit/assets/dm-sans-latin-500-normal-B9HHJjqV.woff2 +0 -0
  99. package/cockpit/assets/dm-sans-latin-500-normal-Dr3UlScf.woff +0 -0
  100. package/cockpit/assets/dm-sans-latin-700-normal-CUSSCpQX.woff +0 -0
  101. package/cockpit/assets/dm-sans-latin-700-normal-DvUfVpUG.woff2 +0 -0
  102. package/cockpit/assets/dm-sans-latin-ext-400-normal-BjWJ59Pq.woff +0 -0
  103. package/cockpit/assets/dm-sans-latin-ext-400-normal-BtiwyxMk.woff2 +0 -0
  104. package/cockpit/assets/dm-sans-latin-ext-500-normal-BJfUCQsA.woff2 +0 -0
  105. package/cockpit/assets/dm-sans-latin-ext-500-normal-DR84L5F-.woff +0 -0
  106. package/cockpit/assets/dm-sans-latin-ext-700-normal-BLI3TTWz.woff +0 -0
  107. package/cockpit/assets/dm-sans-latin-ext-700-normal-CJIcxD6K.woff2 +0 -0
  108. package/cockpit/assets/index-DDswO4B1.css +1 -0
  109. package/cockpit/assets/index-bovtnZ98.js +18 -0
  110. package/cockpit/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
  111. package/cockpit/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
  112. package/cockpit/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
  113. package/cockpit/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
  114. package/cockpit/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  115. package/cockpit/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  116. package/cockpit/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
  117. package/cockpit/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
  118. package/cockpit/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
  119. package/cockpit/assets/outfit-latin-400-normal-BGsTXAXT.woff2 +0 -0
  120. package/cockpit/assets/outfit-latin-400-normal-DMwTpYkH.woff +0 -0
  121. package/cockpit/assets/outfit-latin-600-normal-B7SfZ07L.woff2 +0 -0
  122. package/cockpit/assets/outfit-latin-600-normal-BEfTtDA7.woff +0 -0
  123. package/cockpit/assets/outfit-latin-ext-400-normal-5tcqmc2S.woff2 +0 -0
  124. package/cockpit/assets/outfit-latin-ext-400-normal-DHm7mdGe.woff +0 -0
  125. package/cockpit/assets/outfit-latin-ext-600-normal-B85nYjL1.woff2 +0 -0
  126. package/cockpit/assets/outfit-latin-ext-600-normal-CWJcPgd7.woff +0 -0
  127. package/cockpit/assets/unbounded-cyrillic-600-normal-B-s5c2Kn.woff +0 -0
  128. package/cockpit/assets/unbounded-cyrillic-600-normal-DW6uzIMB.woff2 +0 -0
  129. package/cockpit/assets/unbounded-latin-600-normal-BPdB_PEv.woff +0 -0
  130. package/cockpit/assets/unbounded-latin-600-normal-oRSANpZr.woff2 +0 -0
  131. package/cockpit/assets/unbounded-latin-ext-600-normal-0iZLtTDV.woff2 +0 -0
  132. package/cockpit/assets/unbounded-latin-ext-600-normal-ClMPf-bu.woff +0 -0
  133. package/cockpit/assets/unbounded-vietnamese-600-normal-BzfrgZ_C.woff +0 -0
  134. package/cockpit/assets/unbounded-vietnamese-600-normal-Cx2bTSHN.woff2 +0 -0
  135. package/cockpit/community.module-inventory.json +2389 -0
  136. package/cockpit/index.html +14 -0
  137. package/community-postgres.json +13 -0
  138. package/migrations/agentspace/0000_thin_carlie_cooper.sql +764 -0
  139. package/migrations/agentspace/meta/0000_snapshot.json +6885 -0
  140. package/migrations/agentspace/meta/_journal.json +13 -0
  141. package/migrations/chatv3/0000_dry_ego.sql +218 -0
  142. package/migrations/chatv3/0001_nosy_obadiah_stane.sql +35 -0
  143. package/migrations/chatv3/0002_narrow_darkhawk.sql +4 -0
  144. package/migrations/chatv3/0003_damp_zarek.sql +2 -0
  145. package/migrations/chatv3/0004_nervous_martin_li.sql +60 -0
  146. package/migrations/chatv3/0005_chatv3_server_encrypted_mode.sql +1 -0
  147. package/migrations/chatv3/meta/0000_snapshot.json +1887 -0
  148. package/migrations/chatv3/meta/0001_snapshot.json +2175 -0
  149. package/migrations/chatv3/meta/0002_snapshot.json +2229 -0
  150. package/migrations/chatv3/meta/0003_snapshot.json +2241 -0
  151. package/migrations/chatv3/meta/0004_snapshot.json +2746 -0
  152. package/migrations/chatv3/meta/_journal.json +48 -0
  153. package/migrations/docman/0000_curvy_valeria_richards.sql +257 -0
  154. package/migrations/docman/0001_massive_risque.sql +2 -0
  155. package/migrations/docman/0002_simple_logan.sql +50 -0
  156. package/migrations/docman/0003_quick_index.sql +45 -0
  157. package/migrations/docman/0004_known_summary.sql +9 -0
  158. package/migrations/docman/0005_vector_signal.sql +9 -0
  159. package/migrations/docman/0006_document_version_current_invariant.sql +15 -0
  160. package/migrations/docman/meta/_journal.json +55 -0
  161. package/migrations/projectman/0000_smooth_klaw.sql +257 -0
  162. package/migrations/projectman/0001_worthless_zodiak.sql +9 -0
  163. package/migrations/projectman/0002_board_rename.sql +108 -0
  164. package/migrations/projectman/0003_review_request.sql +62 -0
  165. package/migrations/projectman/0004_review_request_idempotency.sql +3 -0
  166. package/migrations/projectman/0005_allow_multi_sprint_per_task.sql +1 -0
  167. package/migrations/projectman/meta/_journal.json +48 -0
  168. package/migrations/sys/0000_loose_praxagora.sql +31 -0
  169. package/migrations/sys/0001_awesome_ronan.sql +2 -0
  170. package/migrations/sys/0002_steady_maximus.sql +2 -0
  171. package/migrations/sys/0003_escalating_rate_limiter.sql +2 -0
  172. package/migrations/sys/0004_rate_limiter_timestamptz.sql +22 -0
  173. package/migrations/sys/0005_sys_counters.sql +21 -0
  174. package/migrations/sys/meta/_journal.json +48 -0
  175. package/npm-shrinkwrap.json +4375 -0
  176. package/package.json +62 -0
  177. package/runtime/agentspace-host-adapter.mjs +64 -0
  178. package/runtime/agentspace-tooling.mjs +389 -0
  179. package/runtime/docman-host-adapter.mjs +177 -0
  180. package/runtime/docman-policy.mjs +450 -0
  181. package/runtime/docman-tooling.mjs +20 -0
  182. package/runtime/projectman-host-adapter.mjs +597 -0
  183. package/runtime/scope-context.mjs +99 -0
  184. package/scripts/community-host.mjs +626 -0
  185. package/scripts/community-migration-policy-v1.json +296 -0
@@ -0,0 +1,597 @@
1
+ // @ts-nocheck
2
+ import { createProjectmanPlugin as createBaseProjectmanPlugin } from '@aopslab/domain-host-plugin-projectman'
3
+ import {
4
+ clearProjectmanKitEnvConfigCache,
5
+ clearProjectmanKitOperationCaches,
6
+ runProjectmanKitOperationByTypedId,
7
+ } from '@aopslab/domain-kit-projectman'
8
+ import { runAgentspaceKitOperationByTypedId } from '@aopslab/domain-kit-agentspace'
9
+ import {
10
+ applyProjectmanRuntimeEnv,
11
+ resolveProjectmanRuntimeConfig,
12
+ } from '@aopslab/domain-runtime-config-projectman'
13
+ import { createAgentspaceScopeResolver, toNonEmptyString } from './scope-context.mjs'
14
+
15
+ const DEFAULT_RESUME_MEMORY_LIMIT = 8
16
+ const DEFAULT_RESUME_MEMORY_CANDIDATE_LIMIT = 48
17
+ const OPEN_ISSUE_STATUSES = new Set(['open', 'triaged', 'in_progress'])
18
+ const OPEN_FEEDBACK_STATUSES = new Set(['new', 'triaged', 'planned'])
19
+ let projectmanHostedRuntimeEnvReady = false
20
+ let projectmanHostedStorageReadyPromise = null
21
+
22
+ function assertProjectmanHostRuntimeStorage(runtime) {
23
+ if (runtime?.repoUrlSource === 'default-sqlite' || runtime?.repoDialect === 'sqlite') {
24
+ throw new Error(
25
+ 'projectman_host_runtime_storage_unbound:Set PROJECTMAN_REPO_URL, PROJECTMAN_PG_URL, AOPS_REPO_URL, or AOPS_PG_URL to PostgreSQL before starting AOPS server.',
26
+ )
27
+ }
28
+ }
29
+
30
+ function ensureProjectmanHostedRuntimeEnv(options = {}) {
31
+ if (projectmanHostedRuntimeEnvReady) return
32
+
33
+ clearProjectmanKitEnvConfigCache()
34
+ clearProjectmanKitOperationCaches()
35
+
36
+ const repoUrlOverride =
37
+ toNonEmptyString(process.env.PROJECTMAN_REPO_URL) ??
38
+ toNonEmptyString(process.env.PROJECTMAN_SQLITE_URL) ??
39
+ toNonEmptyString(process.env.PROJECTMAN_PG_URL) ??
40
+ toNonEmptyString(process.env.AOPS_REPO_URL) ??
41
+ toNonEmptyString(process.env.AOPS_SQLITE_URL) ??
42
+ toNonEmptyString(process.env.AOPS_PG_URL)
43
+
44
+ const runtime = resolveProjectmanRuntimeConfig(
45
+ {
46
+ repoUrl: repoUrlOverride,
47
+ projectId: options.defaultProjectId,
48
+ },
49
+ process.env,
50
+ )
51
+
52
+ assertProjectmanHostRuntimeStorage(runtime)
53
+
54
+ applyProjectmanRuntimeEnv(
55
+ {
56
+ runtimeMode: runtime.runtimeMode,
57
+ repoUrl: runtime.repoUrl,
58
+ repoDialect: runtime.repoDialect,
59
+ projectId: runtime.projectId,
60
+ },
61
+ process.env,
62
+ )
63
+
64
+ clearProjectmanKitEnvConfigCache()
65
+ clearProjectmanKitOperationCaches()
66
+ if (process.env.AOPS_DB_BOOTSTRAP_MODE !== 'explicit') {
67
+ throw new Error('community_strict_bootstrap_mode_required');
68
+ }
69
+ projectmanHostedStorageReadyPromise = Promise.resolve();
70
+ projectmanHostedRuntimeEnvReady = true
71
+ }
72
+
73
+ async function ensureProjectmanHostedStorageReady() {
74
+ if (projectmanHostedStorageReadyPromise) {
75
+ await projectmanHostedStorageReadyPromise
76
+ }
77
+ }
78
+
79
+ function toStringArray(values) {
80
+ if (!Array.isArray(values)) return []
81
+ return values.map((item) => String(item ?? '').trim()).filter(Boolean)
82
+ }
83
+
84
+ function toArray(value) {
85
+ return Array.isArray(value) ? value : []
86
+ }
87
+
88
+ function compactRecord(value) {
89
+ return Object.fromEntries(Object.entries(toRecord(value)).filter(([, item]) => item !== undefined))
90
+ }
91
+
92
+ function uniqueStrings(values) {
93
+ const seen = new Set()
94
+ const result = []
95
+ for (const value of values) {
96
+ const normalized = toNonEmptyString(value)
97
+ if (!normalized || seen.has(normalized)) continue
98
+ seen.add(normalized)
99
+ result.push(normalized)
100
+ }
101
+ return result
102
+ }
103
+
104
+ function toRecord(value) {
105
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return {}
106
+ return value
107
+ }
108
+
109
+ const projectmanScopeResolver = createAgentspaceScopeResolver({
110
+ runAgentspaceOperation: runAgentspaceKitOperationByTypedId,
111
+ })
112
+
113
+ async function resolveProjectOwnerContext(projectId) {
114
+ const owner = await projectmanScopeResolver.resolveProjectContext(projectId)
115
+ if (owner.scopeId) return owner
116
+ const safeProjectId = toNonEmptyString(projectId)
117
+ return {
118
+ ...owner,
119
+ projectId: owner.projectId ?? safeProjectId,
120
+ scopeId: owner.scopeId ?? safeProjectId,
121
+ }
122
+ }
123
+
124
+ function toImportance(value) {
125
+ if (typeof value === 'number' && Number.isFinite(value)) return value
126
+ if (typeof value === 'string' && value.trim()) {
127
+ const parsed = Number(value)
128
+ if (Number.isFinite(parsed)) return parsed
129
+ }
130
+ return undefined
131
+ }
132
+
133
+ function unwrapData(value) {
134
+ const record = toRecord(value)
135
+ if (Object.prototype.hasOwnProperty.call(record, 'data')) {
136
+ return record.data
137
+ }
138
+ return value
139
+ }
140
+
141
+ function toResultArray(value) {
142
+ const data = unwrapData(value)
143
+ if (Array.isArray(data)) return data
144
+ const record = toRecord(data)
145
+ if (Array.isArray(record.items)) return record.items
146
+ return []
147
+ }
148
+
149
+ function isNotCompletedMicrotask(item) {
150
+ const status = toNonEmptyString(item?.status)?.toLowerCase()
151
+ return status !== 'completed' && status !== 'cancelled'
152
+ }
153
+
154
+ function isActiveSprint(item) {
155
+ const status = toNonEmptyString(item?.status)?.toLowerCase()
156
+ return status !== 'completed' && status !== 'cancelled'
157
+ }
158
+
159
+ function isOpenIssue(item) {
160
+ const status = toNonEmptyString(item?.status)?.toLowerCase()
161
+ return !!status && OPEN_ISSUE_STATUSES.has(status)
162
+ }
163
+
164
+ function isOpenFeedback(item) {
165
+ const status = toNonEmptyString(item?.status)?.toLowerCase()
166
+ return !!status && OPEN_FEEDBACK_STATUSES.has(status)
167
+ }
168
+
169
+ function pickPrimaryResumeMicrotask(items) {
170
+ const rows = toArray(items)
171
+ return (
172
+ rows.find((item) => toNonEmptyString(item?.status)?.toLowerCase() === 'doing') ??
173
+ rows.find((item) => toNonEmptyString(item?.status)?.toLowerCase() === 'blocked') ??
174
+ rows.find((item) => toNonEmptyString(item?.id)) ??
175
+ null
176
+ )
177
+ }
178
+
179
+ function pickPrimaryEntity(items) {
180
+ return toArray(items).find((item) => toNonEmptyString(item?.id)) ?? null
181
+ }
182
+
183
+ function buildResumeSubject(type, id, label) {
184
+ const subject = compactRecord({
185
+ type: toNonEmptyString(type),
186
+ id: toNonEmptyString(id),
187
+ label: toNonEmptyString(label),
188
+ })
189
+ return Object.keys(subject).length > 0 ? subject : undefined
190
+ }
191
+
192
+ function appendSourceReference(sourceTypes, sourceIds, type, id) {
193
+ const safeType = toNonEmptyString(type)
194
+ const safeId = toNonEmptyString(id)
195
+ if (!safeType || !safeId) return
196
+ sourceTypes.push(safeType)
197
+ sourceIds.push(safeId)
198
+ }
199
+
200
+ function appendMicrotaskLineageSourceRefs(sourceTypes, sourceIds, microtask, options = {}) {
201
+ appendSourceReference(sourceTypes, sourceIds, 'projectman.microtask', microtask?.id)
202
+ if (options.includeSprint !== false) {
203
+ appendSourceReference(sourceTypes, sourceIds, 'projectman.sprint', microtask?.sprintId)
204
+ }
205
+ appendSourceReference(sourceTypes, sourceIds, 'projectman.kanban-task', microtask?.kanbanTaskId)
206
+ }
207
+
208
+ function buildProjectmanMemoryTags({ baseTags = [], projectId, sprintId, phaseId, kanbanTaskId, microtaskId }) {
209
+ return uniqueStrings([
210
+ ...toStringArray(baseTags),
211
+ projectId ? `project:${projectId}` : undefined,
212
+ sprintId ? `sprint:${sprintId}` : undefined,
213
+ phaseId ? `phase:${phaseId}` : undefined,
214
+ kanbanTaskId ? `kanban-task:${kanbanTaskId}` : undefined,
215
+ microtaskId ? `microtask:${microtaskId}` : undefined,
216
+ ])
217
+ }
218
+
219
+ function buildProjectmanMemoryMeta({
220
+ projectId,
221
+ subjectType,
222
+ subjectId,
223
+ subjectTitle,
224
+ sprintId,
225
+ phaseId,
226
+ kanbanTaskId,
227
+ microtaskId,
228
+ nextAction,
229
+ nextReadRefs,
230
+ validationState,
231
+ sourceRefs,
232
+ extra,
233
+ }) {
234
+ return compactRecord({
235
+ projectId: toNonEmptyString(projectId),
236
+ subjectType: toNonEmptyString(subjectType),
237
+ subjectId: toNonEmptyString(subjectId),
238
+ subjectTitle: toNonEmptyString(subjectTitle),
239
+ sprintId: toNonEmptyString(sprintId),
240
+ phaseId: toNonEmptyString(phaseId),
241
+ kanbanTaskId: toNonEmptyString(kanbanTaskId),
242
+ microtaskId: toNonEmptyString(microtaskId),
243
+ nextAction: toNonEmptyString(nextAction),
244
+ nextReadRefs: toArray(nextReadRefs),
245
+ validationState: toNonEmptyString(validationState),
246
+ sourceRefs: toArray(sourceRefs),
247
+ synchronizedAt: new Date().toISOString(),
248
+ ...compactRecord(toRecord(extra)),
249
+ })
250
+ }
251
+
252
+ function buildProjectmanResumeMemoryRetrieval({ activeSprints, incompleteMicrotasks, openIssues, openFeedback }) {
253
+ const primaryMicrotask = pickPrimaryResumeMicrotask(incompleteMicrotasks)
254
+ const primarySprint = pickPrimaryEntity(activeSprints)
255
+ const primaryIssue = pickPrimaryEntity(openIssues)
256
+ const primaryFeedback = pickPrimaryEntity(openFeedback)
257
+
258
+ let query = 'resume project context'
259
+ let runtimeProfile = 'planning'
260
+ let subject
261
+
262
+ const sourceTypes = []
263
+ const sourceIds = []
264
+
265
+ if (primaryMicrotask) {
266
+ query = 'resume implementation handoff'
267
+ runtimeProfile = 'implementation'
268
+ subject = buildResumeSubject('projectman.microtask', primaryMicrotask.id, primaryMicrotask.title)
269
+ appendMicrotaskLineageSourceRefs(sourceTypes, sourceIds, primaryMicrotask)
270
+ } else if (primarySprint) {
271
+ query = 'resume active sprint context'
272
+ runtimeProfile = 'planning'
273
+ subject = buildResumeSubject('projectman.sprint', primarySprint.id, primarySprint.name)
274
+ appendSourceReference(sourceTypes, sourceIds, 'projectman.sprint', primarySprint.id)
275
+ } else if (primaryIssue) {
276
+ query = 'resume open issue context'
277
+ runtimeProfile = 'investigation'
278
+ subject = buildResumeSubject('projectman.issue', primaryIssue.id, primaryIssue.title)
279
+ appendSourceReference(sourceTypes, sourceIds, 'projectman.issue', primaryIssue.id)
280
+ } else if (primaryFeedback) {
281
+ query = 'resume feedback triage context'
282
+ runtimeProfile = 'feedback-triage'
283
+ subject = buildResumeSubject('projectman.feedback', primaryFeedback.id, primaryFeedback.title)
284
+ appendSourceReference(sourceTypes, sourceIds, 'projectman.feedback', primaryFeedback.id)
285
+ }
286
+
287
+ if (primarySprint && !sourceIds.includes(primarySprint.id)) {
288
+ appendSourceReference(sourceTypes, sourceIds, 'projectman.sprint', primarySprint.id)
289
+ }
290
+
291
+ return compactRecord({
292
+ query,
293
+ runtimeProfile,
294
+ subject,
295
+ tags: uniqueStrings([
296
+ 'phase:memory',
297
+ primaryMicrotask ? 'resume:implementation' : undefined,
298
+ primarySprint ? 'resume:sprint' : undefined,
299
+ primaryIssue ? 'resume:issue' : undefined,
300
+ primaryFeedback ? 'resume:feedback' : undefined,
301
+ ]),
302
+ sourceTypes: uniqueStrings(sourceTypes),
303
+ sourceIds: uniqueStrings(sourceIds),
304
+ candidateLimit: DEFAULT_RESUME_MEMORY_CANDIDATE_LIMIT,
305
+ })
306
+ }
307
+
308
+ function shouldWritebackOnSprintCompletion(operationId, input, output) {
309
+ if (operationId !== 'sprint.update') return false
310
+ const requestedStatus = toNonEmptyString(input?.status)?.toLowerCase()
311
+ if (requestedStatus !== 'completed') return false
312
+ const updatedStatus = toNonEmptyString(output?.status)?.toLowerCase()
313
+ return updatedStatus === 'completed'
314
+ }
315
+
316
+ function shouldWritebackOnMicrotaskCompletion(operationId, input, output) {
317
+ if (operationId !== 'microtask.update') return false
318
+ const requestedStatus = toNonEmptyString(input?.status)?.toLowerCase()
319
+ if (requestedStatus !== 'completed') return false
320
+ const updatedStatus = toNonEmptyString(output?.status)?.toLowerCase()
321
+ return updatedStatus === 'completed'
322
+ }
323
+
324
+ function buildMemoryContent(sprint) {
325
+ const sprintName = toNonEmptyString(sprint?.name) ?? 'Unnamed sprint'
326
+ const sprintGoal = toNonEmptyString(sprint?.goal) ?? 'No goal'
327
+ const endedAt = toNonEmptyString(sprint?.endAt)
328
+ if (endedAt) {
329
+ return `Sprint "${sprintName}" completed. Goal: ${sprintGoal}. End date: ${endedAt}.`
330
+ }
331
+ return `Sprint "${sprintName}" completed. Goal: ${sprintGoal}.`
332
+ }
333
+
334
+ function buildSummaryText(sprint) {
335
+ const sprintName = toNonEmptyString(sprint?.name) ?? 'Unnamed sprint'
336
+ const sprintGoal = toNonEmptyString(sprint?.goal) ?? 'No goal'
337
+ return `Latest completed sprint: ${sprintName}. Goal: ${sprintGoal}.`
338
+ }
339
+
340
+ function ensureTrailingSentence(value) {
341
+ const normalized = toNonEmptyString(value)
342
+ if (!normalized) return undefined
343
+ return /[.!?]$/.test(normalized) ? normalized : `${normalized}.`
344
+ }
345
+
346
+ function buildMicrotaskMemoryContent(microtask) {
347
+ const microtaskTitle = toNonEmptyString(microtask?.title) ?? 'Unnamed microtask'
348
+ const notes = toNonEmptyString(microtask?.notes)
349
+ const closedAt = toNonEmptyString(microtask?.closedAt)
350
+ const parts = [`Microtask "${microtaskTitle}" completed.`]
351
+ const noteSentence = ensureTrailingSentence(notes)
352
+ if (noteSentence) parts.push(`Notes: ${noteSentence}`)
353
+ if (closedAt) parts.push(`Closed at: ${closedAt}.`)
354
+ return parts.join(' ')
355
+ }
356
+
357
+ async function listIncompleteMicrotasksForActiveSprints(projectId, activeSprints) {
358
+ return toArray(activeSprints).flatMap((sprint) => {
359
+ const sprintId = toNonEmptyString(sprint?.id)
360
+ return toArray(sprint?.phases).flatMap((phase) =>
361
+ toArray(phase?.microtasks)
362
+ .filter(isNotCompletedMicrotask)
363
+ .map((microtask) => ({
364
+ ...toRecord(microtask),
365
+ sprintId: toNonEmptyString(microtask?.sprintId) || sprintId,
366
+ phaseId: toNonEmptyString(microtask?.phaseId) || toNonEmptyString(phase?.id),
367
+ kanbanTaskId: toNonEmptyString(microtask?.kanbanTaskId) || toNonEmptyString(sprint?.kanbanTaskId),
368
+ })),
369
+ )
370
+ })
371
+ }
372
+
373
+ export async function buildProjectmanResumeContextPack({ projectId }) {
374
+ const safeProjectId = toNonEmptyString(projectId)
375
+ if (!safeProjectId) {
376
+ throw new Error('missing_project_id_for_resume_context_pack')
377
+ }
378
+ const ownerContext = await resolveProjectOwnerContext(safeProjectId)
379
+ const ownerScopeId = toNonEmptyString(ownerContext.scopeId) ?? safeProjectId
380
+
381
+ const [activeSprintsRaw, issueItemsRaw, feedbackItemsRaw] = await Promise.all([
382
+ runProjectmanKitOperationByTypedId('sprint.list', {
383
+ scopeId: ownerScopeId,
384
+ }),
385
+ runProjectmanKitOperationByTypedId('issue.list', {
386
+ scopeId: ownerScopeId,
387
+ }),
388
+ runProjectmanKitOperationByTypedId('feedback.list', {
389
+ scopeId: ownerScopeId,
390
+ }),
391
+ ])
392
+
393
+ const activeSprints = toArray(activeSprintsRaw).filter(isActiveSprint)
394
+ const incompleteMicrotasks = await listIncompleteMicrotasksForActiveSprints(safeProjectId, activeSprints)
395
+ const openIssues = toArray(issueItemsRaw).filter(isOpenIssue)
396
+ const openFeedback = toArray(feedbackItemsRaw).filter(isOpenFeedback)
397
+ const resumePack = toRecord(
398
+ unwrapData(
399
+ await runAgentspaceKitOperationByTypedId('memory-item.build-resume-pack', {
400
+ filter: { scopeId: ownerScopeId, scopeResolution: 'cascade', projectId: safeProjectId },
401
+ retrieval: buildProjectmanResumeMemoryRetrieval({
402
+ activeSprints,
403
+ incompleteMicrotasks,
404
+ openIssues,
405
+ openFeedback,
406
+ }),
407
+ options: { depth: 'light', limit: DEFAULT_RESUME_MEMORY_LIMIT },
408
+ })
409
+ )
410
+ )
411
+ const memoryItems = toResultArray(resumePack.relatedMemory).slice(0, DEFAULT_RESUME_MEMORY_LIMIT)
412
+ const synopsis = toRecord(resumePack.synopsis)
413
+ const bootstrapGuidance = uniqueStrings(toArray(resumePack.bootstrapGuidance)).slice(0, 3)
414
+
415
+ return {
416
+ generatedAt: new Date().toISOString(),
417
+ projectId: safeProjectId,
418
+ synopsis: Object.keys(synopsis).length > 0 ? synopsis : null,
419
+ bootstrapGuidance,
420
+ resumePack: Object.keys(resumePack).length > 0 ? resumePack : null,
421
+ memoryItems,
422
+ activeSprints,
423
+ incompleteMicrotasks,
424
+ openIssues,
425
+ openFeedback,
426
+ }
427
+ }
428
+
429
+ async function writebackSprintCompletionToAops(sprint) {
430
+ const projectId = toNonEmptyString(sprint?.projectId)
431
+ const ownerContext = await resolveProjectOwnerContext(projectId)
432
+ const scopeId = toNonEmptyString(ownerContext.scopeId) ?? projectId
433
+ const sprintId = toNonEmptyString(sprint?.id)
434
+ if (!projectId || !scopeId || !sprintId) return
435
+
436
+ const tags = buildProjectmanMemoryTags({
437
+ baseTags: [
438
+ 'phase:memory',
439
+ 'phase:closeout',
440
+ 'source:projectman',
441
+ ...toStringArray(sprint?.tags).map((tag) => `sprint-tag:${tag}`),
442
+ ],
443
+ projectId,
444
+ sprintId,
445
+ })
446
+
447
+ await runAgentspaceKitOperationByTypedId('memory-item.add-memory-item', {
448
+ data: {
449
+ scopeId,
450
+ kind: 'closeout',
451
+ durability: 'short',
452
+ content: buildMemoryContent(sprint),
453
+ tags,
454
+ importance: 70,
455
+ sourceType: 'projectman.sprint',
456
+ sourceId: sprintId,
457
+ meta: buildProjectmanMemoryMeta({
458
+ projectId,
459
+ subjectType: 'projectman.sprint',
460
+ subjectId: sprintId,
461
+ subjectTitle: sprint?.name,
462
+ sprintId,
463
+ validationState: toNonEmptyString(sprint?.status),
464
+ extra: {
465
+ sprintName: toNonEmptyString(sprint?.name),
466
+ sprintGoal: toNonEmptyString(sprint?.goal),
467
+ sprintStatus: toNonEmptyString(sprint?.status),
468
+ },
469
+ }),
470
+ },
471
+ })
472
+
473
+ const resumeContextPack = await buildProjectmanResumeContextPack({ projectId })
474
+ const openItems = [
475
+ `Active sprints: ${resumeContextPack.activeSprints.length}`,
476
+ `Incomplete microtasks: ${resumeContextPack.incompleteMicrotasks.length}`,
477
+ `Open issues: ${resumeContextPack.openIssues.length}`,
478
+ `Open feedback: ${resumeContextPack.openFeedback.length}`,
479
+ ]
480
+ if (openItems.length > 0) {
481
+ await runAgentspaceKitOperationByTypedId('memory-item.add-memory-item', {
482
+ data: {
483
+ scopeId,
484
+ kind: 'note',
485
+ durability: 'durable',
486
+ content: `${buildSummaryText(sprint)} ${openItems.join('. ')}.`,
487
+ tags: buildProjectmanMemoryTags({
488
+ baseTags: ['phase:memory', 'phase:note', 'source:projectman'],
489
+ projectId,
490
+ sprintId,
491
+ }),
492
+ importance: 50,
493
+ sourceType: 'projectman.sprint',
494
+ sourceId: sprintId,
495
+ meta: buildProjectmanMemoryMeta({
496
+ projectId,
497
+ subjectType: 'projectman.sprint',
498
+ subjectId: sprintId,
499
+ subjectTitle: sprint?.name,
500
+ sprintId,
501
+ extra: { openItems },
502
+ }),
503
+ },
504
+ })
505
+ }
506
+ }
507
+
508
+ async function writebackMicrotaskCompletionToAops(microtask) {
509
+ const projectId = toNonEmptyString(microtask?.projectId)
510
+ const ownerContext = await resolveProjectOwnerContext(projectId)
511
+ const scopeId = toNonEmptyString(ownerContext.scopeId) ?? projectId
512
+ const microtaskId = toNonEmptyString(microtask?.id)
513
+ if (!projectId || !scopeId || !microtaskId) return
514
+
515
+ const sprintId = toNonEmptyString(microtask?.sprintId)
516
+ const phaseId = toNonEmptyString(microtask?.phaseId)
517
+ const kanbanTaskId = toNonEmptyString(microtask?.kanbanTaskId)
518
+
519
+ await runAgentspaceKitOperationByTypedId('memory-item.add-memory-item', {
520
+ data: {
521
+ scopeId,
522
+ kind: 'note',
523
+ content: buildMicrotaskMemoryContent(microtask),
524
+ tags: buildProjectmanMemoryTags({
525
+ baseTags: ['phase:memory', 'phase:closeout', 'source:projectman'],
526
+ projectId,
527
+ sprintId,
528
+ phaseId,
529
+ kanbanTaskId,
530
+ microtaskId,
531
+ }),
532
+ durability: 'short',
533
+ importance: 60,
534
+ sourceType: 'projectman.microtask',
535
+ sourceId: microtaskId,
536
+ meta: buildProjectmanMemoryMeta({
537
+ projectId,
538
+ subjectType: 'projectman.microtask',
539
+ subjectId: microtaskId,
540
+ subjectTitle: microtask?.title,
541
+ sprintId,
542
+ phaseId,
543
+ kanbanTaskId,
544
+ microtaskId,
545
+ validationState: toNonEmptyString(microtask?.status),
546
+ extra: {
547
+ microtaskStatus: toNonEmptyString(microtask?.status),
548
+ notes: toNonEmptyString(microtask?.notes),
549
+ closedAt: toNonEmptyString(microtask?.closedAt),
550
+ },
551
+ }),
552
+ },
553
+ })
554
+ }
555
+
556
+ export function createProjectmanPlugin(options = {}) {
557
+ ensureProjectmanHostedRuntimeEnv(options)
558
+
559
+ const projectmanRunner =
560
+ typeof options.runner === 'function'
561
+ ? options.runner
562
+ : (operationId, input) => runProjectmanKitOperationByTypedId(operationId, input)
563
+
564
+ const enableAopsWriteback = options.enableAopsWriteback !== false
565
+ const failOnWritebackError = options.failOnWritebackError === true
566
+
567
+ const wrappedRunner = async (operationId, input) => {
568
+ await ensureProjectmanHostedStorageReady()
569
+ const output = await projectmanRunner(operationId, input)
570
+
571
+ if (enableAopsWriteback) {
572
+ try {
573
+ if (shouldWritebackOnSprintCompletion(operationId, input, output)) {
574
+ await writebackSprintCompletionToAops(output)
575
+ }
576
+ if (shouldWritebackOnMicrotaskCompletion(operationId, input, output)) {
577
+ await writebackMicrotaskCompletionToAops(output)
578
+ }
579
+ } catch (error) {
580
+ const message = error instanceof Error ? error.message : String(error)
581
+ console.warn('[projectman-host-adapter] aops writeback failed', {
582
+ operationId,
583
+ message,
584
+ })
585
+ if (failOnWritebackError) throw error
586
+ }
587
+ }
588
+
589
+
590
+ return output
591
+ }
592
+
593
+ return createBaseProjectmanPlugin({
594
+ defaultProjectId: options.defaultProjectId,
595
+ runner: wrappedRunner,
596
+ })
597
+ }
@@ -0,0 +1,99 @@
1
+ // @ts-nocheck
2
+ export function toNonEmptyString(value) {
3
+ if (typeof value !== 'string') return undefined
4
+ const trimmed = value.trim()
5
+ return trimmed.length > 0 ? trimmed : undefined
6
+ }
7
+
8
+ function toRecord(value) {
9
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return {}
10
+ return value
11
+ }
12
+
13
+ function unwrapData(value) {
14
+ const record = toRecord(value)
15
+ if (Object.prototype.hasOwnProperty.call(record, 'data')) {
16
+ return record.data
17
+ }
18
+ return value
19
+ }
20
+
21
+ export function normalizeScopeResolution(value) {
22
+ return value === 'cascade' || value === 'explicit' ? value : undefined
23
+ }
24
+
25
+ export function createAgentspaceScopeResolver(params) {
26
+ const projectCache = new Map()
27
+ const runAgentspaceOperation = params.runAgentspaceOperation
28
+ const normalizeScopeId = params.normalizeScopeId ?? toNonEmptyString
29
+
30
+ async function resolveProjectContext(projectId) {
31
+ const normalizedProjectId = toNonEmptyString(projectId)
32
+ if (!normalizedProjectId) {
33
+ return {
34
+ projectId: undefined,
35
+ scopeId: undefined,
36
+ }
37
+ }
38
+
39
+ if (projectCache.has(normalizedProjectId)) {
40
+ return projectCache.get(normalizedProjectId)
41
+ }
42
+
43
+ const projectRecord = toRecord(
44
+ unwrapData(
45
+ await runAgentspaceOperation('project.get-by-id', {
46
+ id: normalizedProjectId,
47
+ }).catch(() => null),
48
+ ),
49
+ )
50
+
51
+ const context = {
52
+ projectId: normalizedProjectId,
53
+ scopeId: normalizeScopeId(projectRecord.scopeId) ?? toNonEmptyString(projectRecord.id) ?? normalizedProjectId,
54
+ }
55
+ projectCache.set(normalizedProjectId, context)
56
+ return context
57
+ }
58
+
59
+ async function resolveRequestScope(requestContext = {}, options = {}) {
60
+ const explicitScopeId = normalizeScopeId(requestContext.scopeId)
61
+ const scopeResolution = normalizeScopeResolution(requestContext.scopeResolution)
62
+
63
+ if (explicitScopeId) {
64
+ return {
65
+ projectId: toNonEmptyString(requestContext.projectId),
66
+ scopeId: explicitScopeId,
67
+ scopeResolution,
68
+ }
69
+ }
70
+
71
+ const projectContext = await resolveProjectContext(requestContext.projectId)
72
+ if (projectContext.scopeId) {
73
+ return {
74
+ projectId: projectContext.projectId,
75
+ scopeId: projectContext.scopeId,
76
+ scopeResolution,
77
+ }
78
+ }
79
+
80
+ const defaultProjectId = toNonEmptyString(options.defaultProjectId)
81
+ const defaultScopeId = normalizeScopeId(options.defaultScopeId)
82
+
83
+ return {
84
+ projectId: defaultProjectId ?? projectContext.projectId,
85
+ scopeId: defaultScopeId ?? defaultProjectId ?? projectContext.scopeId,
86
+ scopeResolution,
87
+ }
88
+ }
89
+
90
+ function clearCaches() {
91
+ projectCache.clear()
92
+ }
93
+
94
+ return {
95
+ resolveProjectContext,
96
+ resolveRequestScope,
97
+ clearCaches,
98
+ }
99
+ }