@aopslabs/aops 0.3.31 → 0.3.33

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 (147) hide show
  1. package/README.md +11 -3
  2. package/aops-assets-release/aops-assets.json.gz +0 -0
  3. package/aops-assets-release/disciplines/build-review-chat/SKILL.md +33 -0
  4. package/aops-assets-release/disciplines/coordinator-loop/SKILL.md +33 -0
  5. package/aops-assets-release/disciplines/design-first-consensus/SKILL.md +30 -0
  6. package/aops-assets-release/disciplines/solo-pm-loop/SKILL.md +31 -0
  7. package/aops-assets-release/docs/user-guides/agentspace-user-guide.md +384 -0
  8. package/aops-assets-release/docs/user-guides/aops-cli-user-guide.md +2067 -0
  9. package/aops-assets-release/docs/user-guides/chatv3-user-guide.md +500 -0
  10. package/aops-assets-release/docs/user-guides/docman-user-guide.md +1009 -0
  11. package/aops-assets-release/docs/user-guides/projectman-user-guide.md +763 -0
  12. package/aops-assets-release/docs/user-guides/tasker-user-guide.md +244 -0
  13. package/aops-assets-release/release.json +6 -0
  14. package/aops-assets-release/roles/coordinator/ROLE.md +28 -0
  15. package/aops-assets-release/roles/implementer/ROLE.md +27 -0
  16. package/aops-assets-release/roles/reviewer/ROLE.md +27 -0
  17. package/aops-assets-release/skills/aops/SKILL.md +112 -0
  18. package/aops-assets-release/skills/aops-bootstrapper-authoring/SKILL.md +245 -0
  19. package/aops-assets-release/skills/aops-cli-agentspace/SKILL.md +186 -0
  20. package/aops-assets-release/skills/aops-cli-board-lifecycle/SKILL.md +64 -0
  21. package/aops-assets-release/skills/aops-cli-chat/SKILL.md +204 -0
  22. package/aops-assets-release/skills/aops-cli-collab/SKILL.md +42 -0
  23. package/aops-assets-release/skills/aops-cli-core/SKILL.md +219 -0
  24. package/aops-assets-release/skills/aops-cli-discuss/SKILL.md +172 -0
  25. package/aops-assets-release/skills/aops-cli-docman/SKILL.md +192 -0
  26. package/aops-assets-release/skills/aops-cli-fileman/SKILL.md +169 -0
  27. package/aops-assets-release/skills/aops-cli-mission/SKILL.md +128 -0
  28. package/aops-assets-release/skills/aops-cli-operator-brief/SKILL.md +67 -0
  29. package/aops-assets-release/skills/aops-cli-projectman/SKILL.md +235 -0
  30. package/aops-assets-release/skills/aops-cli-sugar-authoring/SKILL.md +188 -0
  31. package/aops-assets-release/skills/aops-cli-tasker/SKILL.md +108 -0
  32. package/aops-assets-release/skills/aops-cli-tooling-agent/SKILL.md +112 -0
  33. package/aops-assets-release/skills/aops-cli-view/SKILL.md +210 -0
  34. package/aops-assets-release/skills/aops-collaborative-work/SKILL.md +304 -0
  35. package/aops-assets-release/skills/aops-interactive/SKILL.md +70 -0
  36. package/aops-assets-release/skills/aops-loop-interactive/SKILL.md +314 -0
  37. package/aops-assets-release/skills/aops-working-disciplines/SKILL.md +310 -0
  38. package/aops-assets-release/skills/feature-retirement-flow/SKILL.md +126 -0
  39. package/assets/skills/aops-install/SKILL.md +18 -17
  40. package/dist/commands/assets.js +93 -1264
  41. package/dist/commands/community-server.js +27 -8
  42. package/dist/commands/community-setup.js +1 -2
  43. package/dist/commands/discuss.js +1 -1
  44. package/dist/commands/doc.js +88 -27
  45. package/dist/commands/docs.js +68 -0
  46. package/dist/commands/global-update.js +28 -0
  47. package/dist/commands/init.js +3 -1
  48. package/dist/commands/loop.js +6379 -0
  49. package/dist/commands/memory.js +2 -1
  50. package/dist/commands/pm/index.js +11 -9
  51. package/dist/commands/pm/projectman.js +33 -2
  52. package/dist/commands/project.js +6 -6
  53. package/dist/commands/prompt.js +1 -1
  54. package/dist/commands/repo-sync.js +92 -27
  55. package/dist/commands/runner.js +257 -0
  56. package/dist/commands/skill.js +1 -1
  57. package/dist/commands/start.js +1 -1
  58. package/dist/commands/tasker.js +361 -0
  59. package/dist/commands/view.js +53 -9
  60. package/dist/lib/commercial-setup-readiness-adapter.js +0 -1
  61. package/dist/lib/community-migration-snapshot.js +7 -9
  62. package/dist/lib/community-native-database-recovery.js +5 -14
  63. package/dist/lib/community-native-lifecycle.js +13 -0
  64. package/dist/lib/setup-agent-assets-bridge.js +28 -148
  65. package/dist/lib/setup-agent-assets-release.js +16 -44
  66. package/dist/lib/setup-init-orchestrator.js +11 -15
  67. package/dist/lib/simple-agent-assets.js +447 -0
  68. package/dist/lib/user-guide-sections.js +488 -0
  69. package/dist/main.js +10 -2
  70. package/dist/seeds/agents-md.js +3 -3
  71. package/dist/utils/agents-md.js +1 -1
  72. package/dist/utils/guide-paths.js +7 -7
  73. package/dist/utils/hosted-workspace.js +2 -1
  74. package/dist/utils/repo-first-storage.js +26 -1
  75. package/dist/utils/session-state.js +2 -7
  76. package/launchers/aops-cockpit.sh +0 -0
  77. package/launchers/aops-server.sh +0 -0
  78. package/package.json +67 -35
  79. package/THIRD_PARTY_NOTICES +0 -16169
  80. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/SKILL.md +0 -47
  81. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/agentspace/SKILL.md +0 -72
  82. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/aops-cli-core/SKILL.md +0 -110
  83. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/chatv3/SKILL.md +0 -59
  84. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/collaborative-work/SKILL.md +0 -81
  85. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/discuss/SKILL.md +0 -66
  86. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/docman/SKILL.md +0 -75
  87. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/projectman/SKILL.md +0 -92
  88. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/sys/SKILL.md +0 -36
  89. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/view/SKILL.md +0 -58
  90. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/working-disciplines/SKILL.md +0 -66
  91. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/agent-assets.md +0 -81
  92. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/agentspace.md +0 -183
  93. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/aops-cli.md +0 -1108
  94. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/aops-system.md +0 -102
  95. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/chatv3.md +0 -113
  96. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/docman.md +0 -223
  97. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/projectman.md +0 -233
  98. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/sys.md +0 -94
  99. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/working-disciplines.md +0 -482
  100. package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/manifest.json +0 -117
  101. package/agent-assets-release/agent-assets/gateway/aops/SKILL.md +0 -14
  102. package/agent-assets-release/agent-assets/inventory.json +0 -29
  103. package/agent-assets-release/agent-assets/projection.json +0 -8
  104. package/agent-assets-release/agent-assets-release.json +0 -171
  105. package/agent-assets-release/agent-assets-release.sigstore.json +0 -67
  106. package/assets/agent-assets/core/SKILL.md +0 -47
  107. package/assets/agent-assets/core/references/agentspace/SKILL.md +0 -72
  108. package/assets/agent-assets/core/references/aops-cli-core/SKILL.md +0 -110
  109. package/assets/agent-assets/core/references/chatv3/SKILL.md +0 -59
  110. package/assets/agent-assets/core/references/collaborative-work/SKILL.md +0 -81
  111. package/assets/agent-assets/core/references/discuss/SKILL.md +0 -66
  112. package/assets/agent-assets/core/references/docman/SKILL.md +0 -75
  113. package/assets/agent-assets/core/references/projectman/SKILL.md +0 -92
  114. package/assets/agent-assets/core/references/sys/SKILL.md +0 -36
  115. package/assets/agent-assets/core/references/view/SKILL.md +0 -58
  116. package/assets/agent-assets/core/references/working-disciplines/SKILL.md +0 -66
  117. package/assets/agent-assets/core/user-guides/agent-assets.md +0 -81
  118. package/assets/agent-assets/core/user-guides/agentspace.md +0 -183
  119. package/assets/agent-assets/core/user-guides/aops-cli.md +0 -1108
  120. package/assets/agent-assets/core/user-guides/aops-system.md +0 -102
  121. package/assets/agent-assets/core/user-guides/chatv3.md +0 -113
  122. package/assets/agent-assets/core/user-guides/docman.md +0 -223
  123. package/assets/agent-assets/core/user-guides/projectman.md +0 -233
  124. package/assets/agent-assets/core/user-guides/sys.md +0 -94
  125. package/assets/agent-assets/core/user-guides/working-disciplines.md +0 -482
  126. package/assets/agent-assets/gateway/aops/SKILL.md +0 -14
  127. package/dist/lib/agent-assets/gateway.js +0 -15
  128. package/dist/lib/agent-assets/guards.js +0 -23
  129. package/dist/lib/agent-assets/hosted-discovery.js +0 -148
  130. package/dist/lib/agent-assets/hosted-package-input.js +0 -154
  131. package/dist/lib/agent-assets/legacy-pointer-migration.js +0 -677
  132. package/dist/lib/agent-assets/native-fs.js +0 -589
  133. package/dist/lib/agent-assets/roots.js +0 -45
  134. package/dist/lib/agent-assets/runtime-binding-reader.js +0 -545
  135. package/dist/lib/agent-assets/runtime-targets.js +0 -50
  136. package/dist/lib/agent-assets/store-reader.js +0 -1212
  137. package/dist/lib/agent-assets/store-writer.js +0 -1484
  138. package/native/bin/darwin-arm64/aops-agent-assets-fs +0 -0
  139. package/native/bin/darwin-x64/aops-agent-assets-fs +0 -0
  140. package/native/bin/linux-arm64/aops-agent-assets-fs +0 -0
  141. package/native/bin/linux-x64/aops-agent-assets-fs +0 -0
  142. package/native/bin/win32-x64/aops-agent-assets-fs.exe +0 -0
  143. package/native/manifest.json +0 -49
  144. package/native/qualifications/win32-x64.json +0 -23
  145. package/native/tui/darwin-arm64/aops-tui +0 -0
  146. package/native/tui/linux-x64/aops-tui +0 -0
  147. package/native/tui/win32-x64/aops-tui.exe +0 -0
@@ -0,0 +1,447 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import { cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, writeFileSync, } from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { gunzipSync } from 'node:zlib';
6
+ import { compareCanonicalText } from '@aopslabs/artifact-trust-contracts';
7
+ const RELEASE_INDEX = 'release.json';
8
+ const MAX_ARCHIVE_BYTES = 16 * 1024 * 1024;
9
+ const MAX_UNPACKED_BYTES = 64 * 1024 * 1024;
10
+ const MAX_FILE_BYTES = 2 * 1024 * 1024;
11
+ const MAX_FILES = 512;
12
+ const VERSION_PATTERN = /^[a-z0-9][a-z0-9._-]{0,127}$/i;
13
+ const SKILL_PATTERN = /^(?:aops(?:-[a-z0-9]+)*|feature-retirement-flow)$/;
14
+ const PRIVATE_SKILL_NAME_PATTERN = /^aops-(?:private|release)-/;
15
+ const PRIVATE_ASSET_MARKER = /must never enter public AOPS agent assets/iu;
16
+ export const AOPS_ASSETS_REPOSITORY = 'eeemzs/aops';
17
+ export const SIMPLE_AGENT_ASSETS_RUNTIME_IDS = ['codex', 'claude'];
18
+ function fail(message) {
19
+ throw new Error(`aops_assets_${message}`);
20
+ }
21
+ function sha256(bytes) {
22
+ return createHash('sha256').update(bytes).digest('hex');
23
+ }
24
+ function readJson(file) {
25
+ try {
26
+ return JSON.parse(readFileSync(file, 'utf8'));
27
+ }
28
+ catch {
29
+ return fail(`invalid_json:${path.basename(file)}`);
30
+ }
31
+ }
32
+ function asRecord(value) {
33
+ if (!value || typeof value !== 'object' || Array.isArray(value))
34
+ fail('invalid_record');
35
+ return value;
36
+ }
37
+ function validateVersion(value) {
38
+ if (typeof value !== 'string' || !VERSION_PATTERN.test(value))
39
+ fail('invalid_version');
40
+ return value;
41
+ }
42
+ function validateArchiveName(value) {
43
+ if (typeof value !== 'string' || value !== path.basename(value) || !value.endsWith('.json.gz')) {
44
+ fail('invalid_archive_name');
45
+ }
46
+ return value;
47
+ }
48
+ function validateSha256(value) {
49
+ if (typeof value !== 'string' || !/^[a-f0-9]{64}$/.test(value))
50
+ fail('invalid_archive_sha256');
51
+ return value;
52
+ }
53
+ export function readSimpleAgentAssetsReleaseIndex(releaseRoot) {
54
+ const normalizedRoot = path.resolve(releaseRoot);
55
+ const rootStat = lstatSync(normalizedRoot);
56
+ const indexPath = path.join(normalizedRoot, RELEASE_INDEX);
57
+ const indexStat = lstatSync(indexPath);
58
+ if (!rootStat.isDirectory() || rootStat.isSymbolicLink() || !indexStat.isFile() || indexStat.isSymbolicLink()) {
59
+ fail('invalid_release_root');
60
+ }
61
+ const record = asRecord(readJson(indexPath));
62
+ if (record.schemaVersion !== 2)
63
+ fail('unsupported_release_index');
64
+ return Object.freeze({
65
+ schemaVersion: 2,
66
+ version: validateVersion(record.version),
67
+ archive: validateArchiveName(record.archive),
68
+ sha256: validateSha256(record.sha256),
69
+ });
70
+ }
71
+ function validateAssetPath(value) {
72
+ if (typeof value !== 'string' || value.length === 0 || value.includes('\\') || path.posix.isAbsolute(value)) {
73
+ fail('unsafe_asset_path');
74
+ }
75
+ const segments = value.split('/');
76
+ if (segments.some((segment) => !segment || segment === '.' || segment === '..'))
77
+ fail('unsafe_asset_path');
78
+ if (segments[0] === 'skills') {
79
+ if (segments.length < 3 || !SKILL_PATTERN.test(segments[1]) || PRIVATE_SKILL_NAME_PATTERN.test(segments[1])) {
80
+ fail('private_or_invalid_skill');
81
+ }
82
+ }
83
+ else if (segments[0] === 'docs') {
84
+ if (segments.length !== 3 || segments[1] !== 'user-guides' || !/^[a-z0-9]+(?:-[a-z0-9]+)*-user-guide\.md$/u.test(segments[2])) {
85
+ fail('invalid_user_guide_path');
86
+ }
87
+ }
88
+ else if (segments[0] === 'disciplines') {
89
+ if (segments.length !== 3 || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/u.test(segments[1]) || segments[2] !== 'SKILL.md') {
90
+ fail('invalid_discipline_path');
91
+ }
92
+ }
93
+ else if (segments[0] === 'roles') {
94
+ if (segments.length !== 3 || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/u.test(segments[1]) || segments[2] !== 'ROLE.md') {
95
+ fail('invalid_role_path');
96
+ }
97
+ }
98
+ else {
99
+ fail('invalid_asset_kind');
100
+ }
101
+ return value;
102
+ }
103
+ function decodeArchive(bytes, expectedVersion) {
104
+ let inflated;
105
+ try {
106
+ inflated = gunzipSync(bytes, { maxOutputLength: MAX_UNPACKED_BYTES });
107
+ }
108
+ catch {
109
+ return fail('invalid_archive');
110
+ }
111
+ let archiveValue;
112
+ try {
113
+ archiveValue = JSON.parse(inflated.toString('utf8'));
114
+ }
115
+ catch {
116
+ return fail('invalid_archive_json');
117
+ }
118
+ const archive = asRecord(archiveValue);
119
+ if (archive.schemaVersion !== 2 || validateVersion(archive.version) !== expectedVersion || !Array.isArray(archive.files)) {
120
+ fail('invalid_archive_contract');
121
+ }
122
+ if (archive.files.length === 0 || archive.files.length > MAX_FILES)
123
+ fail('invalid_archive_file_count');
124
+ const exactPaths = new Set();
125
+ const foldedPaths = new Set();
126
+ const files = archive.files.map((candidate) => {
127
+ const row = asRecord(candidate);
128
+ const assetPath = validateAssetPath(row.path);
129
+ const folded = assetPath.toLowerCase();
130
+ if (exactPaths.has(assetPath) || foldedPaths.has(folded))
131
+ fail('duplicate_asset_path');
132
+ exactPaths.add(assetPath);
133
+ foldedPaths.add(folded);
134
+ if (typeof row.content !== 'string')
135
+ fail('invalid_asset_content');
136
+ const fileBytes = Buffer.from(row.content, 'base64');
137
+ if (fileBytes.toString('base64') !== row.content)
138
+ fail('invalid_asset_content');
139
+ if (fileBytes.byteLength > MAX_FILE_BYTES)
140
+ fail('asset_too_large');
141
+ return Object.freeze({ path: assetPath, bytes: fileBytes });
142
+ });
143
+ const ordered = files.sort((left, right) => compareCanonicalText(left.path, right.path));
144
+ for (const file of ordered) {
145
+ if (file.path.startsWith('skills/') && file.path.endsWith('/SKILL.md') && PRIVATE_ASSET_MARKER.test(file.bytes.toString('utf8'))) {
146
+ fail('private_or_invalid_skill');
147
+ }
148
+ }
149
+ return Object.freeze(ordered);
150
+ }
151
+ export function loadSimpleAgentAssetsRelease(releaseRoot) {
152
+ const normalizedRoot = path.resolve(releaseRoot);
153
+ const index = readSimpleAgentAssetsReleaseIndex(normalizedRoot);
154
+ const archivePath = path.join(normalizedRoot, index.archive);
155
+ const archiveStat = lstatSync(archivePath);
156
+ if (!archiveStat.isFile() || archiveStat.isSymbolicLink() || archiveStat.size > MAX_ARCHIVE_BYTES) {
157
+ fail('invalid_archive_file');
158
+ }
159
+ const archiveBytes = readFileSync(archivePath);
160
+ if (sha256(archiveBytes) !== index.sha256)
161
+ fail('archive_digest_mismatch');
162
+ const files = decodeArchive(archiveBytes, index.version);
163
+ const skillNames = Object.freeze([...new Set(files
164
+ .filter((file) => file.path.startsWith('skills/'))
165
+ .map((file) => file.path.split('/')[1]))].sort(compareCanonicalText));
166
+ const userGuidePaths = Object.freeze(files
167
+ .filter((file) => file.path.startsWith('docs/user-guides/'))
168
+ .map((file) => file.path)
169
+ .sort(compareCanonicalText));
170
+ const disciplineNames = Object.freeze([...new Set(files
171
+ .filter((file) => file.path.startsWith('disciplines/'))
172
+ .map((file) => file.path.split('/')[1]))].sort(compareCanonicalText));
173
+ const roleNames = Object.freeze([...new Set(files
174
+ .filter((file) => file.path.startsWith('roles/'))
175
+ .map((file) => file.path.split('/')[1]))].sort(compareCanonicalText));
176
+ for (const skill of skillNames) {
177
+ if (!files.some((file) => file.path === `skills/${skill}/SKILL.md`))
178
+ fail(`skill_entry_missing:${skill}`);
179
+ }
180
+ for (const discipline of disciplineNames) {
181
+ if (!files.some((file) => file.path === `disciplines/${discipline}/SKILL.md`))
182
+ fail(`discipline_entry_missing:${discipline}`);
183
+ }
184
+ for (const role of roleNames) {
185
+ if (!files.some((file) => file.path === `roles/${role}/ROLE.md`))
186
+ fail(`role_entry_missing:${role}`);
187
+ }
188
+ if (skillNames.length === 0 || userGuidePaths.length === 0)
189
+ fail('incomplete_public_asset_set');
190
+ return Object.freeze({ releaseRoot: normalizedRoot, index, archivePath, files, skillNames, userGuidePaths, disciplineNames, roleNames });
191
+ }
192
+ export function resolveSimpleAgentAssetsRoots(options = {}) {
193
+ const env = options.env ?? process.env;
194
+ const home = path.resolve(options.homeDir ?? os.homedir());
195
+ const aopsDataRoot = path.resolve(options.dataRoot ?? env.AOPS_DATA_ROOT ?? path.join(home, '.aops'));
196
+ return Object.freeze({
197
+ storeRoot: path.join(aopsDataRoot, 'assets'),
198
+ runtimeHomes: Object.freeze({
199
+ codex: path.resolve(options.codexHome ?? env.CODEX_HOME ?? path.join(home, '.codex')),
200
+ claude: path.resolve(options.claudeHome ?? env.CLAUDE_HOME ?? path.join(home, '.claude')),
201
+ }),
202
+ });
203
+ }
204
+ export function resolveSimpleAgentAssetsTargets(target) {
205
+ if (target === undefined || target === 'all')
206
+ return SIMPLE_AGENT_ASSETS_RUNTIME_IDS;
207
+ const values = Array.isArray(target) ? target : [target];
208
+ const selected = new Set(values);
209
+ if ([...selected].some((value) => !SIMPLE_AGENT_ASSETS_RUNTIME_IDS.includes(value))) {
210
+ fail('invalid_target');
211
+ }
212
+ return Object.freeze(SIMPLE_AGENT_ASSETS_RUNTIME_IDS.filter((runtime) => selected.has(runtime)));
213
+ }
214
+ function statePath(roots) {
215
+ return path.join(roots.storeRoot, 'state.json');
216
+ }
217
+ export function readSimpleAgentAssetsState(roots) {
218
+ const file = statePath(roots);
219
+ if (!existsSync(file))
220
+ return Object.freeze({ schemaVersion: 1, current: null, previous: null, updatedAt: null });
221
+ const record = asRecord(readJson(file));
222
+ if (record.schemaVersion !== 1)
223
+ fail('unsupported_state');
224
+ const current = record.current === null ? null : validateVersion(record.current);
225
+ const previous = record.previous === null ? null : validateVersion(record.previous);
226
+ const updatedAt = record.updatedAt === null || typeof record.updatedAt === 'string' ? record.updatedAt : fail('invalid_state');
227
+ return Object.freeze({ schemaVersion: 1, current, previous, updatedAt });
228
+ }
229
+ function writeState(roots, state) {
230
+ mkdirSync(roots.storeRoot, { recursive: true });
231
+ const temporary = `${statePath(roots)}.${randomUUID()}.tmp`;
232
+ writeFileSync(temporary, `${JSON.stringify(state, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 });
233
+ renameSync(temporary, statePath(roots));
234
+ }
235
+ function storedReleaseRoot(roots, version) {
236
+ return path.join(roots.storeRoot, 'releases', validateVersion(version));
237
+ }
238
+ function legacyStoreRoot(roots) {
239
+ return path.join(path.dirname(roots.storeRoot), 'agent-assets');
240
+ }
241
+ function validateLegacyStore(roots) {
242
+ const legacyRoot = legacyStoreRoot(roots);
243
+ if (!existsSync(legacyRoot))
244
+ return null;
245
+ const stat = lstatSync(legacyRoot);
246
+ if (!stat.isDirectory() || stat.isSymbolicLink())
247
+ fail('unsafe_legacy_store');
248
+ return legacyRoot;
249
+ }
250
+ function writeExtractedFiles(root, release) {
251
+ for (const file of release.files) {
252
+ const destination = path.join(root, 'files', ...file.path.split('/'));
253
+ mkdirSync(path.dirname(destination), { recursive: true });
254
+ writeFileSync(destination, file.bytes, { mode: 0o644 });
255
+ }
256
+ }
257
+ function storeRelease(roots, release) {
258
+ const releasesRoot = path.join(roots.storeRoot, 'releases');
259
+ mkdirSync(releasesRoot, { recursive: true });
260
+ const destination = storedReleaseRoot(roots, release.index.version);
261
+ if (existsSync(destination)) {
262
+ const existing = loadSimpleAgentAssetsRelease(destination);
263
+ if (existing.index.sha256 !== release.index.sha256)
264
+ fail('version_archive_conflict');
265
+ return destination;
266
+ }
267
+ const temporary = mkdtempSync(path.join(releasesRoot, '.stage-'));
268
+ try {
269
+ cpSync(path.join(release.releaseRoot, RELEASE_INDEX), path.join(temporary, RELEASE_INDEX));
270
+ cpSync(release.archivePath, path.join(temporary, release.index.archive));
271
+ writeExtractedFiles(temporary, release);
272
+ renameSync(temporary, destination);
273
+ return destination;
274
+ }
275
+ finally {
276
+ rmSync(temporary, { recursive: true, force: true });
277
+ }
278
+ }
279
+ function backupName() {
280
+ return `${new Date().toISOString().replaceAll(':', '-').replaceAll('.', '-')}-${randomUUID().slice(0, 8)}`;
281
+ }
282
+ function installFiles(storedRoot, release, managedSkillNames, roots, targets, commit) {
283
+ const backupRoot = path.join(roots.storeRoot, 'backups', backupName());
284
+ const changed = [];
285
+ const stages = new Set();
286
+ mkdirSync(backupRoot, { recursive: true });
287
+ try {
288
+ for (const runtime of targets) {
289
+ const skillsRoot = path.join(roots.runtimeHomes[runtime], 'skills');
290
+ for (const skill of managedSkillNames) {
291
+ const destination = path.join(skillsRoot, skill);
292
+ if (!existsSync(destination))
293
+ continue;
294
+ const destinationStat = lstatSync(destination);
295
+ if (!destinationStat.isDirectory() || destinationStat.isSymbolicLink()) {
296
+ fail(`unsafe_existing_skill:${runtime}:${skill}`);
297
+ }
298
+ }
299
+ }
300
+ for (const runtime of targets) {
301
+ const skillsRoot = path.join(roots.runtimeHomes[runtime], 'skills');
302
+ mkdirSync(skillsRoot, { recursive: true });
303
+ for (const skill of managedSkillNames) {
304
+ const destination = path.join(skillsRoot, skill);
305
+ const backup = path.join(backupRoot, runtime, skill);
306
+ const existed = existsSync(destination);
307
+ if (existed) {
308
+ mkdirSync(path.dirname(backup), { recursive: true });
309
+ cpSync(destination, backup, { recursive: true });
310
+ }
311
+ changed.push({ destination, backup, existed });
312
+ rmSync(destination, { recursive: true, force: true });
313
+ if (release.skillNames.includes(skill)) {
314
+ const source = path.join(storedRoot, 'files', 'skills', skill);
315
+ const stage = path.join(skillsRoot, `.aops-assets-${skill}-${randomUUID()}`);
316
+ stages.add(stage);
317
+ cpSync(source, stage, { recursive: true });
318
+ renameSync(stage, destination);
319
+ stages.delete(stage);
320
+ }
321
+ }
322
+ }
323
+ writeFileSync(path.join(backupRoot, 'backup.json'), `${JSON.stringify({
324
+ schemaVersion: 1,
325
+ version: release.index.version,
326
+ targets,
327
+ skills: release.skillNames,
328
+ cleanedSkills: managedSkillNames,
329
+ }, null, 2)}\n`, { mode: 0o600 });
330
+ commit(backupRoot);
331
+ return backupRoot;
332
+ }
333
+ catch (error) {
334
+ for (const stage of stages)
335
+ rmSync(stage, { recursive: true, force: true });
336
+ for (const item of changed.reverse()) {
337
+ rmSync(item.destination, { recursive: true, force: true });
338
+ if (item.existed)
339
+ cpSync(item.backup, item.destination, { recursive: true });
340
+ }
341
+ throw error;
342
+ }
343
+ }
344
+ export function installSimpleAgentAssets(options) {
345
+ const roots = options.roots ?? resolveSimpleAgentAssetsRoots();
346
+ const targets = resolveSimpleAgentAssetsTargets(options.target);
347
+ const release = loadSimpleAgentAssetsRelease(options.releaseRoot);
348
+ const legacyRoot = validateLegacyStore(roots);
349
+ const before = readSimpleAgentAssetsState(roots);
350
+ const previousRelease = before.current
351
+ ? loadSimpleAgentAssetsRelease(storedReleaseRoot(roots, before.current))
352
+ : null;
353
+ const managedSkillNames = Object.freeze([...new Set([
354
+ ...(previousRelease?.skillNames ?? []),
355
+ ...release.skillNames,
356
+ ])].sort(compareCanonicalText));
357
+ const storedRoot = storeRelease(roots, release);
358
+ const sameVersion = before.current === release.index.version;
359
+ const next = Object.freeze({
360
+ schemaVersion: 1,
361
+ current: release.index.version,
362
+ previous: sameVersion ? before.previous : before.current,
363
+ updatedAt: new Date().toISOString(),
364
+ });
365
+ const backupRoot = installFiles(storedRoot, release, managedSkillNames, roots, targets, () => writeState(roots, next));
366
+ if (legacyRoot)
367
+ rmSync(legacyRoot, { recursive: true });
368
+ const assetsRoot = path.join(storedRoot, 'files');
369
+ return Object.freeze({
370
+ version: release.index.version,
371
+ previousVersion: next.previous,
372
+ targets,
373
+ skillCount: release.skillNames.length,
374
+ userGuideCount: release.userGuidePaths.length,
375
+ disciplineCount: release.disciplineNames.length,
376
+ roleCount: release.roleNames.length,
377
+ fileCount: release.files.length,
378
+ assetsRoot,
379
+ userGuidesRoot: path.join(assetsRoot, 'docs', 'user-guides'),
380
+ disciplinesRoot: path.join(assetsRoot, 'disciplines'),
381
+ rolesRoot: path.join(assetsRoot, 'roles'),
382
+ backupRoot,
383
+ repaired: sameVersion,
384
+ legacyStoreRemoved: legacyRoot !== null,
385
+ });
386
+ }
387
+ export function rollbackSimpleAgentAssets(options = {}) {
388
+ const roots = options.roots ?? resolveSimpleAgentAssetsRoots();
389
+ const state = readSimpleAgentAssetsState(roots);
390
+ if (!state.previous)
391
+ fail('previous_release_missing');
392
+ return installSimpleAgentAssets({
393
+ releaseRoot: storedReleaseRoot(roots, state.previous),
394
+ roots,
395
+ target: options.target,
396
+ });
397
+ }
398
+ export async function downloadSimpleAgentAssetsRelease(options = {}) {
399
+ const fetcher = options.fetcher ?? fetch;
400
+ const timeoutMs = options.timeoutMs ?? 30_000;
401
+ const selector = options.tag
402
+ ? `tags/${encodeURIComponent(validateVersion(options.tag))}`
403
+ : 'latest';
404
+ const response = await fetcher(`https://api.github.com/repos/${AOPS_ASSETS_REPOSITORY}/releases/${selector}`, {
405
+ headers: { accept: 'application/vnd.github+json', 'user-agent': 'aops-cli' },
406
+ signal: AbortSignal.timeout(timeoutMs),
407
+ });
408
+ if (!response.ok)
409
+ fail(`github_release_unavailable:${response.status}`);
410
+ const release = asRecord(await response.json());
411
+ if (!Array.isArray(release.assets))
412
+ fail('github_release_assets_missing');
413
+ const assets = new Map(release.assets.map((candidate) => {
414
+ const row = asRecord(candidate);
415
+ return [row.name, row.browser_download_url];
416
+ }));
417
+ const indexUrl = assets.get(RELEASE_INDEX);
418
+ if (typeof indexUrl !== 'string')
419
+ fail('github_release_index_missing');
420
+ const temporary = mkdtempSync(path.join(os.tmpdir(), 'aops-assets-download-'));
421
+ try {
422
+ const indexResponse = await fetcher(indexUrl, { signal: AbortSignal.timeout(timeoutMs) });
423
+ if (!indexResponse.ok)
424
+ fail(`github_release_index_download_failed:${indexResponse.status}`);
425
+ writeFileSync(path.join(temporary, RELEASE_INDEX), Buffer.from(await indexResponse.arrayBuffer()));
426
+ const index = readSimpleAgentAssetsReleaseIndex(temporary);
427
+ const archiveUrl = assets.get(index.archive);
428
+ if (typeof archiveUrl !== 'string')
429
+ fail('github_release_archive_missing');
430
+ const archiveResponse = await fetcher(archiveUrl, { signal: AbortSignal.timeout(timeoutMs) });
431
+ if (!archiveResponse.ok)
432
+ fail(`github_release_archive_download_failed:${archiveResponse.status}`);
433
+ writeFileSync(path.join(temporary, index.archive), Buffer.from(await archiveResponse.arrayBuffer()));
434
+ loadSimpleAgentAssetsRelease(temporary);
435
+ return temporary;
436
+ }
437
+ catch (error) {
438
+ rmSync(temporary, { recursive: true, force: true });
439
+ throw error;
440
+ }
441
+ }
442
+ export function removeDownloadedSimpleAgentAssetsRelease(releaseRoot) {
443
+ const normalized = path.resolve(releaseRoot);
444
+ if (path.basename(normalized).startsWith('aops-assets-download-') && path.dirname(normalized) === os.tmpdir()) {
445
+ rmSync(normalized, { recursive: true, force: true });
446
+ }
447
+ }