@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.
- package/README.md +11 -3
- package/aops-assets-release/aops-assets.json.gz +0 -0
- package/aops-assets-release/disciplines/build-review-chat/SKILL.md +33 -0
- package/aops-assets-release/disciplines/coordinator-loop/SKILL.md +33 -0
- package/aops-assets-release/disciplines/design-first-consensus/SKILL.md +30 -0
- package/aops-assets-release/disciplines/solo-pm-loop/SKILL.md +31 -0
- package/aops-assets-release/docs/user-guides/agentspace-user-guide.md +384 -0
- package/aops-assets-release/docs/user-guides/aops-cli-user-guide.md +2067 -0
- package/aops-assets-release/docs/user-guides/chatv3-user-guide.md +500 -0
- package/aops-assets-release/docs/user-guides/docman-user-guide.md +1009 -0
- package/aops-assets-release/docs/user-guides/projectman-user-guide.md +763 -0
- package/aops-assets-release/docs/user-guides/tasker-user-guide.md +244 -0
- package/aops-assets-release/release.json +6 -0
- package/aops-assets-release/roles/coordinator/ROLE.md +28 -0
- package/aops-assets-release/roles/implementer/ROLE.md +27 -0
- package/aops-assets-release/roles/reviewer/ROLE.md +27 -0
- package/aops-assets-release/skills/aops/SKILL.md +112 -0
- package/aops-assets-release/skills/aops-bootstrapper-authoring/SKILL.md +245 -0
- package/aops-assets-release/skills/aops-cli-agentspace/SKILL.md +186 -0
- package/aops-assets-release/skills/aops-cli-board-lifecycle/SKILL.md +64 -0
- package/aops-assets-release/skills/aops-cli-chat/SKILL.md +204 -0
- package/aops-assets-release/skills/aops-cli-collab/SKILL.md +42 -0
- package/aops-assets-release/skills/aops-cli-core/SKILL.md +219 -0
- package/aops-assets-release/skills/aops-cli-discuss/SKILL.md +172 -0
- package/aops-assets-release/skills/aops-cli-docman/SKILL.md +192 -0
- package/aops-assets-release/skills/aops-cli-fileman/SKILL.md +169 -0
- package/aops-assets-release/skills/aops-cli-mission/SKILL.md +128 -0
- package/aops-assets-release/skills/aops-cli-operator-brief/SKILL.md +67 -0
- package/aops-assets-release/skills/aops-cli-projectman/SKILL.md +235 -0
- package/aops-assets-release/skills/aops-cli-sugar-authoring/SKILL.md +188 -0
- package/aops-assets-release/skills/aops-cli-tasker/SKILL.md +108 -0
- package/aops-assets-release/skills/aops-cli-tooling-agent/SKILL.md +112 -0
- package/aops-assets-release/skills/aops-cli-view/SKILL.md +210 -0
- package/aops-assets-release/skills/aops-collaborative-work/SKILL.md +304 -0
- package/aops-assets-release/skills/aops-interactive/SKILL.md +70 -0
- package/aops-assets-release/skills/aops-loop-interactive/SKILL.md +314 -0
- package/aops-assets-release/skills/aops-working-disciplines/SKILL.md +310 -0
- package/aops-assets-release/skills/feature-retirement-flow/SKILL.md +126 -0
- package/assets/skills/aops-install/SKILL.md +18 -17
- package/dist/commands/assets.js +93 -1264
- package/dist/commands/community-server.js +27 -8
- package/dist/commands/community-setup.js +1 -2
- package/dist/commands/discuss.js +1 -1
- package/dist/commands/doc.js +88 -27
- package/dist/commands/docs.js +68 -0
- package/dist/commands/global-update.js +28 -0
- package/dist/commands/init.js +3 -1
- package/dist/commands/loop.js +6379 -0
- package/dist/commands/memory.js +2 -1
- package/dist/commands/pm/index.js +11 -9
- package/dist/commands/pm/projectman.js +33 -2
- package/dist/commands/project.js +6 -6
- package/dist/commands/prompt.js +1 -1
- package/dist/commands/repo-sync.js +92 -27
- package/dist/commands/runner.js +257 -0
- package/dist/commands/skill.js +1 -1
- package/dist/commands/start.js +1 -1
- package/dist/commands/tasker.js +361 -0
- package/dist/commands/view.js +53 -9
- package/dist/lib/commercial-setup-readiness-adapter.js +0 -1
- package/dist/lib/community-migration-snapshot.js +7 -9
- package/dist/lib/community-native-database-recovery.js +5 -14
- package/dist/lib/community-native-lifecycle.js +13 -0
- package/dist/lib/setup-agent-assets-bridge.js +28 -148
- package/dist/lib/setup-agent-assets-release.js +16 -44
- package/dist/lib/setup-init-orchestrator.js +11 -15
- package/dist/lib/simple-agent-assets.js +447 -0
- package/dist/lib/user-guide-sections.js +488 -0
- package/dist/main.js +10 -2
- package/dist/seeds/agents-md.js +3 -3
- package/dist/utils/agents-md.js +1 -1
- package/dist/utils/guide-paths.js +7 -7
- package/dist/utils/hosted-workspace.js +2 -1
- package/dist/utils/repo-first-storage.js +26 -1
- package/dist/utils/session-state.js +2 -7
- package/launchers/aops-cockpit.sh +0 -0
- package/launchers/aops-server.sh +0 -0
- package/package.json +67 -35
- package/THIRD_PARTY_NOTICES +0 -16169
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/SKILL.md +0 -47
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/agentspace/SKILL.md +0 -72
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/aops-cli-core/SKILL.md +0 -110
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/chatv3/SKILL.md +0 -59
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/collaborative-work/SKILL.md +0 -81
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/discuss/SKILL.md +0 -66
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/docman/SKILL.md +0 -75
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/projectman/SKILL.md +0 -92
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/sys/SKILL.md +0 -36
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/view/SKILL.md +0 -58
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/references/working-disciplines/SKILL.md +0 -66
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/agent-assets.md +0 -81
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/agentspace.md +0 -183
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/aops-cli.md +0 -1108
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/aops-system.md +0 -102
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/chatv3.md +0 -113
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/docman.md +0 -223
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/projectman.md +0 -233
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/sys.md +0 -94
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/files/user-guides/working-disciplines.md +0 -482
- package/agent-assets-release/agent-assets/core/bc42dd7792dbe66040e99a7ef3d80b3bc788c72b369b5a065cf936aef29f53fb/manifest.json +0 -117
- package/agent-assets-release/agent-assets/gateway/aops/SKILL.md +0 -14
- package/agent-assets-release/agent-assets/inventory.json +0 -29
- package/agent-assets-release/agent-assets/projection.json +0 -8
- package/agent-assets-release/agent-assets-release.json +0 -171
- package/agent-assets-release/agent-assets-release.sigstore.json +0 -67
- package/assets/agent-assets/core/SKILL.md +0 -47
- package/assets/agent-assets/core/references/agentspace/SKILL.md +0 -72
- package/assets/agent-assets/core/references/aops-cli-core/SKILL.md +0 -110
- package/assets/agent-assets/core/references/chatv3/SKILL.md +0 -59
- package/assets/agent-assets/core/references/collaborative-work/SKILL.md +0 -81
- package/assets/agent-assets/core/references/discuss/SKILL.md +0 -66
- package/assets/agent-assets/core/references/docman/SKILL.md +0 -75
- package/assets/agent-assets/core/references/projectman/SKILL.md +0 -92
- package/assets/agent-assets/core/references/sys/SKILL.md +0 -36
- package/assets/agent-assets/core/references/view/SKILL.md +0 -58
- package/assets/agent-assets/core/references/working-disciplines/SKILL.md +0 -66
- package/assets/agent-assets/core/user-guides/agent-assets.md +0 -81
- package/assets/agent-assets/core/user-guides/agentspace.md +0 -183
- package/assets/agent-assets/core/user-guides/aops-cli.md +0 -1108
- package/assets/agent-assets/core/user-guides/aops-system.md +0 -102
- package/assets/agent-assets/core/user-guides/chatv3.md +0 -113
- package/assets/agent-assets/core/user-guides/docman.md +0 -223
- package/assets/agent-assets/core/user-guides/projectman.md +0 -233
- package/assets/agent-assets/core/user-guides/sys.md +0 -94
- package/assets/agent-assets/core/user-guides/working-disciplines.md +0 -482
- package/assets/agent-assets/gateway/aops/SKILL.md +0 -14
- package/dist/lib/agent-assets/gateway.js +0 -15
- package/dist/lib/agent-assets/guards.js +0 -23
- package/dist/lib/agent-assets/hosted-discovery.js +0 -148
- package/dist/lib/agent-assets/hosted-package-input.js +0 -154
- package/dist/lib/agent-assets/legacy-pointer-migration.js +0 -677
- package/dist/lib/agent-assets/native-fs.js +0 -589
- package/dist/lib/agent-assets/roots.js +0 -45
- package/dist/lib/agent-assets/runtime-binding-reader.js +0 -545
- package/dist/lib/agent-assets/runtime-targets.js +0 -50
- package/dist/lib/agent-assets/store-reader.js +0 -1212
- package/dist/lib/agent-assets/store-writer.js +0 -1484
- package/native/bin/darwin-arm64/aops-agent-assets-fs +0 -0
- package/native/bin/darwin-x64/aops-agent-assets-fs +0 -0
- package/native/bin/linux-arm64/aops-agent-assets-fs +0 -0
- package/native/bin/linux-x64/aops-agent-assets-fs +0 -0
- package/native/bin/win32-x64/aops-agent-assets-fs.exe +0 -0
- package/native/manifest.json +0 -49
- package/native/qualifications/win32-x64.json +0 -23
- package/native/tui/darwin-arm64/aops-tui +0 -0
- package/native/tui/linux-x64/aops-tui +0 -0
- 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
|
+
}
|