@aopslabs/aops 0.2.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.
- package/LICENSE +19 -0
- package/NOTICE +7 -0
- package/README.md +203 -0
- package/assets/agent-assets/core/SKILL.md +49 -0
- package/assets/agent-assets/core/references/agentspace/SKILL.md +78 -0
- package/assets/agent-assets/core/references/aops-cli-core/SKILL.md +108 -0
- package/assets/agent-assets/core/references/chatv3/SKILL.md +48 -0
- package/assets/agent-assets/core/references/collaborative-work/SKILL.md +85 -0
- package/assets/agent-assets/core/references/discuss/SKILL.md +66 -0
- package/assets/agent-assets/core/references/docman/SKILL.md +69 -0
- package/assets/agent-assets/core/references/hosted-chat/SKILL.md +64 -0
- package/assets/agent-assets/core/references/mission/SKILL.md +54 -0
- package/assets/agent-assets/core/references/projectman/SKILL.md +86 -0
- package/assets/agent-assets/core/references/sys/SKILL.md +36 -0
- package/assets/agent-assets/core/references/view/SKILL.md +58 -0
- package/assets/agent-assets/core/references/working-disciplines/SKILL.md +69 -0
- package/assets/agent-assets/core/user-guides/agent-assets.md +81 -0
- package/assets/agent-assets/core/user-guides/agentspace.md +1098 -0
- package/assets/agent-assets/core/user-guides/aops-cli.md +1107 -0
- package/assets/agent-assets/core/user-guides/aops-system.md +63 -0
- package/assets/agent-assets/core/user-guides/chatv3.md +113 -0
- package/assets/agent-assets/core/user-guides/docman.md +162 -0
- package/assets/agent-assets/core/user-guides/projectman.md +212 -0
- package/assets/agent-assets/core/user-guides/sys.md +94 -0
- package/assets/agent-assets/core/user-guides/working-disciplines.md +588 -0
- package/assets/agent-assets/gateway/aops/SKILL.md +14 -0
- package/assets/r6-remote-session-baseline.json +19 -0
- package/assets/skills/aops-install/SKILL.md +231 -0
- package/assets/skills/aops-install/agents/openai.yaml +4 -0
- package/dist/commands/activity.js +352 -0
- package/dist/commands/agent-profile.js +653 -0
- package/dist/commands/agent.js +710 -0
- package/dist/commands/agents-md.js +125 -0
- package/dist/commands/api.js +84 -0
- package/dist/commands/archive.js +873 -0
- package/dist/commands/artifact.js +535 -0
- package/dist/commands/assets.js +1414 -0
- package/dist/commands/auth/device-login.js +1 -0
- package/dist/commands/auth/legacy-export.js +177 -0
- package/dist/commands/auth/login.js +426 -0
- package/dist/commands/chat.js +1363 -0
- package/dist/commands/chatv3.js +1684 -0
- package/dist/commands/checkpoint.js +549 -0
- package/dist/commands/commercial-artifact.js +475 -0
- package/dist/commands/commercial-license.js +594 -0
- package/dist/commands/community-auth.js +62 -0
- package/dist/commands/community-cockpit.js +185 -0
- package/dist/commands/community-console.js +109 -0
- package/dist/commands/community-doctor.js +335 -0
- package/dist/commands/community-server.js +2062 -0
- package/dist/commands/community-setup.js +284 -0
- package/dist/commands/discuss.js +1448 -0
- package/dist/commands/doc.js +5219 -0
- package/dist/commands/experience.js +922 -0
- package/dist/commands/host.js +1127 -0
- package/dist/commands/init.js +118 -0
- package/dist/commands/memory.js +3129 -0
- package/dist/commands/mission.js +562 -0
- package/dist/commands/official-catalog.js +134 -0
- package/dist/commands/plan.js +84 -0
- package/dist/commands/playbook.js +415 -0
- package/dist/commands/pm/context.js +6 -0
- package/dist/commands/pm/index.js +701 -0
- package/dist/commands/pm/projectman.js +6266 -0
- package/dist/commands/project.js +1080 -0
- package/dist/commands/prompt.js +1024 -0
- package/dist/commands/repo-sync.js +1907 -0
- package/dist/commands/resource.js +527 -0
- package/dist/commands/skill.js +1211 -0
- package/dist/commands/start-disciplines.js +510 -0
- package/dist/commands/start.js +1343 -0
- package/dist/commands/target.js +309 -0
- package/dist/commands/version.js +42 -0
- package/dist/commands/view.js +1852 -0
- package/dist/launchers/cockpit.js +28 -0
- package/dist/launchers/options.js +74 -0
- package/dist/launchers/server.js +41 -0
- package/dist/lib/agent-assets/envelope.js +83 -0
- package/dist/lib/agent-assets/gateway.js +15 -0
- package/dist/lib/agent-assets/guards.js +23 -0
- package/dist/lib/agent-assets/hosted-discovery.js +148 -0
- package/dist/lib/agent-assets/hosted-package-input.js +154 -0
- package/dist/lib/agent-assets/legacy-pointer-migration.js +677 -0
- package/dist/lib/agent-assets/native-fs.js +589 -0
- package/dist/lib/agent-assets/package-manifest.js +324 -0
- package/dist/lib/agent-assets/portable-path.js +67 -0
- package/dist/lib/agent-assets/release-input.js +177 -0
- package/dist/lib/agent-assets/roots.js +45 -0
- package/dist/lib/agent-assets/runtime-binding-reader.js +545 -0
- package/dist/lib/agent-assets/runtime-targets.js +50 -0
- package/dist/lib/agent-assets/store-reader.js +1212 -0
- package/dist/lib/agent-assets/store-types.js +1 -0
- package/dist/lib/agent-assets/store-writer.js +1484 -0
- package/dist/lib/agent-assets/types.js +1 -0
- package/dist/lib/agent-assets/unicode-case-folding-v15-1.generated.js +1548 -0
- package/dist/lib/commercial-final-readiness.js +504 -0
- package/dist/lib/commercial-lifecycle-smoke-isolation.js +236 -0
- package/dist/lib/commercial-managed-postgres-docker-adapter.js +274 -0
- package/dist/lib/commercial-setup-readiness-adapter.js +179 -0
- package/dist/lib/community-client-contract.js +164 -0
- package/dist/lib/community-cockpit-lifecycle.js +601 -0
- package/dist/lib/community-command-abort.js +59 -0
- package/dist/lib/community-diagnostic.js +237 -0
- package/dist/lib/community-docker-adapter.js +498 -0
- package/dist/lib/community-home.js +31 -0
- package/dist/lib/community-instance-contract.js +148 -0
- package/dist/lib/community-instance-layout.js +97 -0
- package/dist/lib/community-lifecycle.js +1631 -0
- package/dist/lib/community-migration-snapshot.js +770 -0
- package/dist/lib/community-native-application-recovery.js +425 -0
- package/dist/lib/community-native-child.js +240 -0
- package/dist/lib/community-native-database-recovery.js +456 -0
- package/dist/lib/community-native-lifecycle.js +2458 -0
- package/dist/lib/community-native-migration.js +339 -0
- package/dist/lib/community-native-postgres.js +596 -0
- package/dist/lib/community-operation-journal.js +773 -0
- package/dist/lib/community-operation-lock.js +596 -0
- package/dist/lib/community-release-resolver.js +291 -0
- package/dist/lib/community-release-verifier.js +475 -0
- package/dist/lib/community-repo-discovery.js +252 -0
- package/dist/lib/community-setup-server-env.js +203 -0
- package/dist/lib/external-url.js +110 -0
- package/dist/lib/official-catalog-gateway.js +108 -0
- package/dist/lib/official-catalog.js +364 -0
- package/dist/lib/server-bootstrap.js +240 -0
- package/dist/lib/setup-agent-assets-bridge.js +176 -0
- package/dist/lib/setup-agent-assets-release.js +52 -0
- package/dist/lib/setup-external-postgres.js +108 -0
- package/dist/lib/setup-init-orchestrator.js +990 -0
- package/dist/lib/setup-install-guide.js +52 -0
- package/dist/lib/setup-installer-release.js +47 -0
- package/dist/lib/setup-local-postgres.js +329 -0
- package/dist/lib/setup-official-catalog-bridge.js +148 -0
- package/dist/lib/setup-readiness.js +888 -0
- package/dist/lib/tui-launcher.js +59 -0
- package/dist/main.js +150 -0
- package/dist/seeds/agents-md.js +54 -0
- package/dist/utils/agent-gateway.js +275 -0
- package/dist/utils/agents-md.js +281 -0
- package/dist/utils/api.js +255 -0
- package/dist/utils/chatv3-session-store.js +185 -0
- package/dist/utils/command.js +67 -0
- package/dist/utils/community-host-runtime.js +376 -0
- package/dist/utils/config.js +1015 -0
- package/dist/utils/discussion-workspace.js +552 -0
- package/dist/utils/experience-workspace.js +326 -0
- package/dist/utils/guide-paths.js +67 -0
- package/dist/utils/hosted-sugar.js +56 -0
- package/dist/utils/hosted-workspace.js +229 -0
- package/dist/utils/memory-workspace.js +537 -0
- package/dist/utils/operator-runtime.js +199 -0
- package/dist/utils/password-crypto.js +39 -0
- package/dist/utils/playbook-workspace.js +479 -0
- package/dist/utils/project-context.js +255 -0
- package/dist/utils/prompts.js +70 -0
- package/dist/utils/refresh-race.js +28 -0
- package/dist/utils/repo-config.js +109 -0
- package/dist/utils/repo-first-projectman.js +194 -0
- package/dist/utils/repo-first-storage.js +13 -0
- package/dist/utils/repo-first-view.js +305 -0
- package/dist/utils/session-guidance.js +278 -0
- package/dist/utils/session-state.js +137 -0
- package/dist/utils/table.js +39 -0
- package/dist/utils/transient-fs.js +49 -0
- package/dist/utils/workspace-root.js +1 -0
- package/launchers/aops-cockpit.ps1 +15 -0
- package/launchers/aops-cockpit.sh +16 -0
- package/launchers/aops-server.ps1 +15 -0
- package/launchers/aops-server.sh +16 -0
- package/native/tui/win32-x64/aops-tui.exe +0 -0
- package/package.json +81 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { lstatSync, readFileSync, realpathSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { TextDecoder } from 'node:util';
|
|
5
|
+
const RELEASE_DIRECTORY = 'release';
|
|
6
|
+
const RELEASE_MANIFEST = 'release.json';
|
|
7
|
+
const MAX_RELEASE_MANIFEST_BYTES = 1024 * 1024;
|
|
8
|
+
const MAX_RELEASE_VERSION_LENGTH = 256;
|
|
9
|
+
const PUBLIC_SOURCE_REPOSITORY = 'git+https://github.com/eeemzs/aops-community';
|
|
10
|
+
const RELEASE_VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?$/;
|
|
11
|
+
const UTF8 = new TextDecoder('utf-8', { fatal: true });
|
|
12
|
+
function fail(code, detail) {
|
|
13
|
+
throw new Error(detail ? `${code}:${detail}` : code);
|
|
14
|
+
}
|
|
15
|
+
function isCanonicalReleaseVersion(value) {
|
|
16
|
+
if (typeof value !== 'string' || value.length > MAX_RELEASE_VERSION_LENGTH)
|
|
17
|
+
return false;
|
|
18
|
+
const match = value.match(RELEASE_VERSION);
|
|
19
|
+
if (!match)
|
|
20
|
+
return false;
|
|
21
|
+
for (const component of match.slice(1, 4)) {
|
|
22
|
+
if (!Number.isSafeInteger(Number(component)))
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
for (const identifier of String(match[4] ?? '').split('.')) {
|
|
26
|
+
if (/^\d+$/.test(identifier) && !Number.isSafeInteger(Number(identifier)))
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
function lstatOrFail(candidate, code) {
|
|
32
|
+
try {
|
|
33
|
+
return lstatSync(candidate);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return fail(code, candidate);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function canonicalPath(candidate, code) {
|
|
40
|
+
try {
|
|
41
|
+
return realpathSync.native(candidate);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return fail(code, candidate);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function lstatBigIntOrFail(candidate, code) {
|
|
48
|
+
try {
|
|
49
|
+
return lstatSync(candidate, { bigint: true });
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return fail(code, candidate);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function sameEntryIdentity(left, right) {
|
|
56
|
+
return left.dev === right.dev
|
|
57
|
+
&& left.ino === right.ino
|
|
58
|
+
&& left.mode === right.mode
|
|
59
|
+
&& left.size === right.size
|
|
60
|
+
&& left.mtimeNs === right.mtimeNs;
|
|
61
|
+
}
|
|
62
|
+
function entrySnapshot(realPath, stat) {
|
|
63
|
+
return Object.freeze({
|
|
64
|
+
realPath,
|
|
65
|
+
device: stat.dev.toString(),
|
|
66
|
+
inode: stat.ino.toString(),
|
|
67
|
+
mode: stat.mode.toString(),
|
|
68
|
+
size: stat.size.toString(),
|
|
69
|
+
modifiedNanoseconds: stat.mtimeNs.toString(),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
function captureEntry(lexicalPath, expectedKind, missingCode, kindCode = expectedKind === 'directory' ? 'community_repo_not_directory' : 'community_repo_marker_not_file') {
|
|
73
|
+
const before = lstatBigIntOrFail(lexicalPath, missingCode);
|
|
74
|
+
if (before.isSymbolicLink())
|
|
75
|
+
fail('community_repo_reparse_refused', lexicalPath);
|
|
76
|
+
if (expectedKind === 'directory' ? !before.isDirectory() : !before.isFile()) {
|
|
77
|
+
fail(kindCode, lexicalPath);
|
|
78
|
+
}
|
|
79
|
+
const resolved = canonicalPath(lexicalPath, 'community_repo_realpath_failed');
|
|
80
|
+
const after = lstatBigIntOrFail(lexicalPath, 'community_repo_snapshot_changed');
|
|
81
|
+
const physical = lstatBigIntOrFail(resolved, 'community_repo_snapshot_changed');
|
|
82
|
+
if (!sameEntryIdentity(before, after) || !sameEntryIdentity(after, physical)) {
|
|
83
|
+
fail('community_repo_snapshot_changed', lexicalPath);
|
|
84
|
+
}
|
|
85
|
+
return entrySnapshot(resolved, after);
|
|
86
|
+
}
|
|
87
|
+
function parseReleaseIdentity(content) {
|
|
88
|
+
if (content.byteLength === 0 || content.byteLength > MAX_RELEASE_MANIFEST_BYTES) {
|
|
89
|
+
fail('community_repo_marker_size_invalid');
|
|
90
|
+
}
|
|
91
|
+
let manifest;
|
|
92
|
+
try {
|
|
93
|
+
manifest = JSON.parse(UTF8.decode(content));
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
fail('community_repo_marker_json_invalid');
|
|
97
|
+
}
|
|
98
|
+
if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest)) {
|
|
99
|
+
fail('community_repo_marker_identity_invalid');
|
|
100
|
+
}
|
|
101
|
+
const candidate = manifest;
|
|
102
|
+
if (candidate.schemaVersion !== 1
|
|
103
|
+
|| !isCanonicalReleaseVersion(candidate.releaseVersion)
|
|
104
|
+
|| candidate.source?.repository !== PUBLIC_SOURCE_REPOSITORY)
|
|
105
|
+
fail('community_repo_marker_identity_invalid');
|
|
106
|
+
return Object.freeze({
|
|
107
|
+
schemaVersion: 1,
|
|
108
|
+
releaseVersion: candidate.releaseVersion,
|
|
109
|
+
sourceRepository: PUBLIC_SOURCE_REPOSITORY,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function assertManifestSnapshotSize(snapshot) {
|
|
113
|
+
let size;
|
|
114
|
+
try {
|
|
115
|
+
size = BigInt(snapshot.size);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return fail('community_repo_marker_size_invalid');
|
|
119
|
+
}
|
|
120
|
+
if (size <= 0n || size > BigInt(MAX_RELEASE_MANIFEST_BYTES)) {
|
|
121
|
+
fail('community_repo_marker_size_invalid');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function sameSnapshot(left, right) {
|
|
125
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
126
|
+
}
|
|
127
|
+
function pathIdentity(candidate) {
|
|
128
|
+
const normalized = path.normalize(candidate);
|
|
129
|
+
return process.platform === 'win32' ? normalized.toLocaleLowerCase('en-US') : normalized;
|
|
130
|
+
}
|
|
131
|
+
function pathsEqual(left, right) {
|
|
132
|
+
return pathIdentity(left) === pathIdentity(right);
|
|
133
|
+
}
|
|
134
|
+
function isConfined(root, candidate) {
|
|
135
|
+
const relative = path.relative(root, candidate);
|
|
136
|
+
return relative === '' || (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative));
|
|
137
|
+
}
|
|
138
|
+
function validateRepoRoot(candidate, source) {
|
|
139
|
+
const lexicalRoot = path.resolve(candidate);
|
|
140
|
+
const lexicalReleaseDir = path.join(lexicalRoot, RELEASE_DIRECTORY);
|
|
141
|
+
const lexicalManifestPath = path.join(lexicalReleaseDir, RELEASE_MANIFEST);
|
|
142
|
+
const rootSnapshot = captureEntry(lexicalRoot, 'directory', 'community_repo_missing');
|
|
143
|
+
const releaseSnapshot = captureEntry(lexicalReleaseDir, 'directory', 'community_repo_marker_missing', 'community_repo_release_not_directory');
|
|
144
|
+
const manifestBeforeRead = captureEntry(lexicalManifestPath, 'file', 'community_repo_marker_missing');
|
|
145
|
+
const repoRoot = rootSnapshot.realPath;
|
|
146
|
+
const releaseDir = releaseSnapshot.realPath;
|
|
147
|
+
const manifestPath = manifestBeforeRead.realPath;
|
|
148
|
+
const expectedReleaseDir = path.join(repoRoot, RELEASE_DIRECTORY);
|
|
149
|
+
const expectedManifestPath = path.join(expectedReleaseDir, RELEASE_MANIFEST);
|
|
150
|
+
if (!pathsEqual(lexicalRoot, repoRoot) ||
|
|
151
|
+
!pathsEqual(releaseDir, expectedReleaseDir) ||
|
|
152
|
+
!pathsEqual(manifestPath, expectedManifestPath) ||
|
|
153
|
+
!isConfined(repoRoot, releaseDir) ||
|
|
154
|
+
!isConfined(releaseDir, manifestPath)) {
|
|
155
|
+
fail('community_repo_marker_escape', lexicalManifestPath);
|
|
156
|
+
}
|
|
157
|
+
assertManifestSnapshotSize(manifestBeforeRead);
|
|
158
|
+
const manifestBytes = readFileSync(manifestPath);
|
|
159
|
+
const manifestAfterRead = captureEntry(lexicalManifestPath, 'file', 'community_repo_marker_missing');
|
|
160
|
+
if (!sameSnapshot(manifestBeforeRead, manifestAfterRead)) {
|
|
161
|
+
fail('community_repo_snapshot_changed', lexicalManifestPath);
|
|
162
|
+
}
|
|
163
|
+
const releaseIdentity = parseReleaseIdentity(manifestBytes);
|
|
164
|
+
return {
|
|
165
|
+
repoRoot,
|
|
166
|
+
releaseDir,
|
|
167
|
+
manifestPath,
|
|
168
|
+
source,
|
|
169
|
+
verification: 'candidate-requires-signed-release-verification',
|
|
170
|
+
releaseIdentity,
|
|
171
|
+
snapshot: Object.freeze({
|
|
172
|
+
schemaVersion: 1,
|
|
173
|
+
root: rootSnapshot,
|
|
174
|
+
release: releaseSnapshot,
|
|
175
|
+
manifest: manifestAfterRead,
|
|
176
|
+
manifestByteLength: manifestBytes.byteLength,
|
|
177
|
+
manifestSha256: `sha256:${createHash('sha256').update(manifestBytes).digest('hex')}`,
|
|
178
|
+
}),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function markerCanBeInspected(candidateRoot) {
|
|
182
|
+
try {
|
|
183
|
+
lstatSync(path.join(candidateRoot, RELEASE_DIRECTORY, RELEASE_MANIFEST));
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
const code = error.code;
|
|
188
|
+
if (code === 'ENOENT' || code === 'ENOTDIR')
|
|
189
|
+
return false;
|
|
190
|
+
return fail('community_repo_marker_inspection_failed', path.join(candidateRoot, RELEASE_DIRECTORY, RELEASE_MANIFEST));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function resolveDiscoveryStart(cwd) {
|
|
194
|
+
const lexicalCwd = path.resolve(cwd);
|
|
195
|
+
const cwdStat = lstatOrFail(lexicalCwd, 'community_repo_cwd_missing');
|
|
196
|
+
if (!cwdStat.isDirectory())
|
|
197
|
+
fail('community_repo_cwd_not_directory', lexicalCwd);
|
|
198
|
+
return canonicalPath(lexicalCwd, 'community_repo_cwd_realpath_failed');
|
|
199
|
+
}
|
|
200
|
+
function discoverCommunityRepo(cwd) {
|
|
201
|
+
let cursor = resolveDiscoveryStart(cwd);
|
|
202
|
+
const matches = new Map();
|
|
203
|
+
while (true) {
|
|
204
|
+
if (markerCanBeInspected(cursor)) {
|
|
205
|
+
const match = validateRepoRoot(cursor, 'discovered');
|
|
206
|
+
matches.set(pathIdentity(match.repoRoot), match);
|
|
207
|
+
}
|
|
208
|
+
const parent = path.dirname(cursor);
|
|
209
|
+
if (parent === cursor)
|
|
210
|
+
break;
|
|
211
|
+
cursor = parent;
|
|
212
|
+
}
|
|
213
|
+
if (matches.size === 0)
|
|
214
|
+
fail('community_repo_not_found', cwd);
|
|
215
|
+
if (matches.size > 1) {
|
|
216
|
+
fail('community_repo_ambiguous', [...matches.values()].map((match) => match.repoRoot).join(','));
|
|
217
|
+
}
|
|
218
|
+
return matches.values().next().value;
|
|
219
|
+
}
|
|
220
|
+
export function resolveCommunityRepo(options = {}) {
|
|
221
|
+
const cwd = options.cwd ?? process.cwd();
|
|
222
|
+
if (options.repo !== undefined) {
|
|
223
|
+
if (typeof options.repo !== 'string' || options.repo.trim() === '')
|
|
224
|
+
fail('community_repo_explicit_invalid');
|
|
225
|
+
const explicitCandidate = path.isAbsolute(options.repo) ? options.repo : path.resolve(cwd, options.repo);
|
|
226
|
+
return validateRepoRoot(explicitCandidate, 'explicit');
|
|
227
|
+
}
|
|
228
|
+
return discoverCommunityRepo(cwd);
|
|
229
|
+
}
|
|
230
|
+
export function assertCommunityRepoCandidateCurrent(resolution) {
|
|
231
|
+
if (!resolution
|
|
232
|
+
|| resolution.verification !== 'candidate-requires-signed-release-verification'
|
|
233
|
+
|| resolution.snapshot?.schemaVersion !== 1)
|
|
234
|
+
fail('community_repo_candidate_invalid');
|
|
235
|
+
const currentRoot = captureEntry(resolution.repoRoot, 'directory', 'community_repo_snapshot_changed');
|
|
236
|
+
const currentRelease = captureEntry(resolution.releaseDir, 'directory', 'community_repo_snapshot_changed', 'community_repo_snapshot_changed');
|
|
237
|
+
const currentManifestBeforeRead = captureEntry(resolution.manifestPath, 'file', 'community_repo_snapshot_changed', 'community_repo_snapshot_changed');
|
|
238
|
+
assertManifestSnapshotSize(currentManifestBeforeRead);
|
|
239
|
+
const manifestBytes = readFileSync(resolution.manifestPath);
|
|
240
|
+
const currentManifestAfterRead = captureEntry(resolution.manifestPath, 'file', 'community_repo_snapshot_changed', 'community_repo_snapshot_changed');
|
|
241
|
+
const manifestSha256 = `sha256:${createHash('sha256').update(manifestBytes).digest('hex')}`;
|
|
242
|
+
const releaseIdentity = parseReleaseIdentity(manifestBytes);
|
|
243
|
+
if (!sameSnapshot(resolution.snapshot.root, currentRoot)
|
|
244
|
+
|| !sameSnapshot(resolution.snapshot.release, currentRelease)
|
|
245
|
+
|| !sameSnapshot(resolution.snapshot.manifest, currentManifestBeforeRead)
|
|
246
|
+
|| !sameSnapshot(currentManifestBeforeRead, currentManifestAfterRead)
|
|
247
|
+
|| manifestBytes.byteLength !== resolution.snapshot.manifestByteLength
|
|
248
|
+
|| manifestSha256 !== resolution.snapshot.manifestSha256
|
|
249
|
+
|| JSON.stringify(releaseIdentity) !== JSON.stringify(resolution.releaseIdentity))
|
|
250
|
+
fail('community_repo_snapshot_changed');
|
|
251
|
+
return resolution;
|
|
252
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { statSync } from 'node:fs';
|
|
2
|
+
import { banner, logInfo, logSuccess } from '@aopslabs/xf-cli-ui';
|
|
3
|
+
import { readAopsServerEnvFileContent, writeAopsServerEnvFileContent, } from '@aopslabs/aops-runtime-config';
|
|
4
|
+
import { promptPassword } from '../utils/prompts.js';
|
|
5
|
+
import { buildServerBootstrapEnvMap, buildServerBootstrapPreset, parseDotEnvAssignments, upsertServerBootstrapBlock, validateServerBootstrapEnv, } from './server-bootstrap.js';
|
|
6
|
+
import { ExternalPostgresProbeError, probeExternalPostgresConnection, } from './setup-external-postgres.js';
|
|
7
|
+
const MAX_POSTGRES_URL_BYTES = 4_096;
|
|
8
|
+
function normalizeNonEmpty(value) {
|
|
9
|
+
if (typeof value !== 'string')
|
|
10
|
+
return undefined;
|
|
11
|
+
const normalized = value.trim();
|
|
12
|
+
return normalized || undefined;
|
|
13
|
+
}
|
|
14
|
+
function resolveServerEnvAuthProvider(requested, existing) {
|
|
15
|
+
const explicit = normalizeNonEmpty(requested);
|
|
16
|
+
const configured = explicit ?? normalizeNonEmpty(existing.AOPS_AUTH_PROVIDER);
|
|
17
|
+
if (configured) {
|
|
18
|
+
if (configured === 'trusted-local')
|
|
19
|
+
return configured;
|
|
20
|
+
if (configured === 'authv2-jwt-session' || configured === 'remote-session') {
|
|
21
|
+
throw new Error('setup_server_env_local_auth_retired:rerun_with_--auth_trusted-local_then_use_a_remote-session_target');
|
|
22
|
+
}
|
|
23
|
+
throw new Error('setup_server_env_auth_provider_invalid:use_trusted-local');
|
|
24
|
+
}
|
|
25
|
+
return 'trusted-local';
|
|
26
|
+
}
|
|
27
|
+
export function resolvePromptedPostgresUrl(promptedValue, savedValue) {
|
|
28
|
+
return normalizeNonEmpty(promptedValue) ?? savedValue;
|
|
29
|
+
}
|
|
30
|
+
function validatePostgresUrl(value) {
|
|
31
|
+
if (/\0|\r|\n/.test(value) || Buffer.byteLength(value, 'utf8') > MAX_POSTGRES_URL_BYTES) {
|
|
32
|
+
throw new Error('setup_server_env_postgres_url_invalid');
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const parsed = new URL(value);
|
|
36
|
+
if (!['postgres:', 'postgresql:'].includes(parsed.protocol) || !parsed.hostname || !parsed.pathname) {
|
|
37
|
+
throw new Error('invalid');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
throw new Error('setup_server_env_postgres_url_invalid');
|
|
42
|
+
}
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
function connectionTestFailure(tlsPolicy, error) {
|
|
46
|
+
const safe = error instanceof ExternalPostgresProbeError
|
|
47
|
+
? error
|
|
48
|
+
: error instanceof Error && error.message.startsWith('setup_server_env_postgres_url_')
|
|
49
|
+
? new ExternalPostgresProbeError(error.message, 'database')
|
|
50
|
+
: new ExternalPostgresProbeError('setup_external_postgres_connection_failed', 'unknown');
|
|
51
|
+
return Object.freeze({
|
|
52
|
+
schemaVersion: 1,
|
|
53
|
+
mutationFree: true,
|
|
54
|
+
ok: false,
|
|
55
|
+
action: 'setup.server-env.test-connection',
|
|
56
|
+
status: 'failed',
|
|
57
|
+
tlsPolicy,
|
|
58
|
+
category: safe.category,
|
|
59
|
+
code: safe.message,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
export async function runCommunitySetupServerEnvConnectionTest(options = {}, dependencies = {}) {
|
|
63
|
+
const tlsPolicy = options.postgresTls ?? 'require';
|
|
64
|
+
const environmentUrl = normalizeNonEmpty(process.env.AOPS_PG_URL)
|
|
65
|
+
?? normalizeNonEmpty(process.env.AOPS_REPO_URL);
|
|
66
|
+
const candidate = normalizeNonEmpty(options.repoUrl) ?? environmentUrl;
|
|
67
|
+
let result;
|
|
68
|
+
try {
|
|
69
|
+
let probeOptions;
|
|
70
|
+
if (candidate) {
|
|
71
|
+
probeOptions = {
|
|
72
|
+
repoUrl: validatePostgresUrl(candidate),
|
|
73
|
+
tlsPolicy,
|
|
74
|
+
timeoutMs: options.timeoutMs,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
const snapshot = readAopsServerEnvFileContent(process.env, options.envPath);
|
|
79
|
+
const existing = parseDotEnvAssignments(snapshot.content);
|
|
80
|
+
const savedUrl = normalizeNonEmpty(existing.AOPS_PG_URL);
|
|
81
|
+
const legacySavedUrl = normalizeNonEmpty(existing.AOPS_REPO_URL);
|
|
82
|
+
if (savedUrl) {
|
|
83
|
+
validatePostgresUrl(savedUrl);
|
|
84
|
+
probeOptions = {
|
|
85
|
+
configRef: snapshot.path,
|
|
86
|
+
tlsPolicy,
|
|
87
|
+
timeoutMs: options.timeoutMs,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
else if (legacySavedUrl) {
|
|
91
|
+
probeOptions = {
|
|
92
|
+
repoUrl: validatePostgresUrl(legacySavedUrl),
|
|
93
|
+
tlsPolicy,
|
|
94
|
+
timeoutMs: options.timeoutMs,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
throw new ExternalPostgresProbeError('setup_server_env_postgres_url_required:configure_or_use_AOPS_PG_URL', 'database');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const probe = await (dependencies.probe ?? probeExternalPostgresConnection)(probeOptions);
|
|
102
|
+
result = Object.freeze({
|
|
103
|
+
schemaVersion: 1,
|
|
104
|
+
mutationFree: true,
|
|
105
|
+
ok: true,
|
|
106
|
+
action: 'setup.server-env.test-connection',
|
|
107
|
+
status: 'ready',
|
|
108
|
+
tlsPolicy: probe.tlsPolicy,
|
|
109
|
+
transport: probe.transport,
|
|
110
|
+
serverMajor: probe.serverMajor,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
result = connectionTestFailure(tlsPolicy, error);
|
|
115
|
+
}
|
|
116
|
+
if (options.json)
|
|
117
|
+
console.log(JSON.stringify(result, null, 2));
|
|
118
|
+
else if (!options.skipBanner) {
|
|
119
|
+
if (result.ok)
|
|
120
|
+
logSuccess(`PostgreSQL ${result.serverMajor} connection is ready.`);
|
|
121
|
+
else
|
|
122
|
+
logInfo(`PostgreSQL connection test failed: ${result.code}`);
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
export async function runCommunitySetupServerEnv(options = {}) {
|
|
127
|
+
const snapshot = readAopsServerEnvFileContent(process.env, options.envPath);
|
|
128
|
+
const existing = parseDotEnvAssignments(snapshot.content);
|
|
129
|
+
const existingUrl = normalizeNonEmpty(existing.AOPS_PG_URL)
|
|
130
|
+
?? normalizeNonEmpty(existing.AOPS_REPO_URL);
|
|
131
|
+
const environmentUrl = normalizeNonEmpty(process.env.AOPS_PG_URL)
|
|
132
|
+
?? normalizeNonEmpty(process.env.AOPS_REPO_URL);
|
|
133
|
+
let repoUrl = normalizeNonEmpty(options.repoUrl) ?? environmentUrl ?? existingUrl;
|
|
134
|
+
if (!options.repoUrl && !options.yes && !options.json) {
|
|
135
|
+
if (!options.skipBanner)
|
|
136
|
+
banner('AOPS Community Server Environment');
|
|
137
|
+
const savedUrl = repoUrl;
|
|
138
|
+
const promptedUrl = await promptPassword({
|
|
139
|
+
message: existingUrl || environmentUrl
|
|
140
|
+
? 'External PostgreSQL URL [saved: ********] (press Enter to keep):'
|
|
141
|
+
: 'External PostgreSQL URL:',
|
|
142
|
+
validate: (value) => {
|
|
143
|
+
if (!value.trim() && savedUrl)
|
|
144
|
+
return true;
|
|
145
|
+
try {
|
|
146
|
+
validatePostgresUrl(value.trim());
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return 'A PostgreSQL URL is required.';
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
repoUrl = resolvePromptedPostgresUrl(promptedUrl, savedUrl);
|
|
155
|
+
}
|
|
156
|
+
if (!repoUrl) {
|
|
157
|
+
throw new Error('setup_server_env_postgres_url_required:use_interactive_prompt_or_AOPS_PG_URL');
|
|
158
|
+
}
|
|
159
|
+
repoUrl = validatePostgresUrl(repoUrl);
|
|
160
|
+
const authProvider = resolveServerEnvAuthProvider(options.auth, existing);
|
|
161
|
+
const preset = buildServerBootstrapPreset({
|
|
162
|
+
authProvider,
|
|
163
|
+
repoUrl,
|
|
164
|
+
existing,
|
|
165
|
+
});
|
|
166
|
+
const env = buildServerBootstrapEnvMap(preset);
|
|
167
|
+
const validation = validateServerBootstrapEnv(env, {
|
|
168
|
+
authProvider: preset.authProvider,
|
|
169
|
+
repoUrl,
|
|
170
|
+
});
|
|
171
|
+
if (!validation.ok || validation.repoDialect !== 'pg') {
|
|
172
|
+
throw new Error('setup_server_env_postgres_validation_failed');
|
|
173
|
+
}
|
|
174
|
+
const content = upsertServerBootstrapBlock({
|
|
175
|
+
existingContent: snapshot.content,
|
|
176
|
+
env,
|
|
177
|
+
authProvider: preset.authProvider,
|
|
178
|
+
repoUrl,
|
|
179
|
+
});
|
|
180
|
+
const updated = content !== snapshot.content;
|
|
181
|
+
const permissionsRepaired = snapshot.exists &&
|
|
182
|
+
process.platform !== 'win32' &&
|
|
183
|
+
(statSync(snapshot.path).mode & 0o777) !== 0o600;
|
|
184
|
+
const envPath = updated || permissionsRepaired
|
|
185
|
+
? writeAopsServerEnvFileContent(content, process.env, options.envPath)
|
|
186
|
+
: snapshot.path;
|
|
187
|
+
const result = Object.freeze({
|
|
188
|
+
ok: true,
|
|
189
|
+
action: 'setup.server-env',
|
|
190
|
+
envPath,
|
|
191
|
+
repoDialect: 'pg',
|
|
192
|
+
authProvider: preset.authProvider,
|
|
193
|
+
updated,
|
|
194
|
+
permissionsRepaired,
|
|
195
|
+
});
|
|
196
|
+
if (options.json)
|
|
197
|
+
console.log(JSON.stringify(result, null, 2));
|
|
198
|
+
else if (!options.skipBanner) {
|
|
199
|
+
logSuccess(updated ? 'Global AOPS server environment is ready.' : 'Global AOPS server environment was already ready.');
|
|
200
|
+
logInfo(`Host env: ${envPath}`);
|
|
201
|
+
}
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
const externalOpenRuntime = Object.freeze({
|
|
3
|
+
spawn,
|
|
4
|
+
handoffTimeoutMs: 1_500,
|
|
5
|
+
});
|
|
6
|
+
function assertLocalHttpUrl(value) {
|
|
7
|
+
const parsed = new URL(value);
|
|
8
|
+
const localHosts = new Set(['127.0.0.1', 'localhost', '[::1]']);
|
|
9
|
+
if (!['http:', 'https:'].includes(parsed.protocol) ||
|
|
10
|
+
!localHosts.has(parsed.hostname) ||
|
|
11
|
+
parsed.username || parsed.password) {
|
|
12
|
+
throw new Error('aops_external_url_refused:only_loopback_http_urls_are_allowed');
|
|
13
|
+
}
|
|
14
|
+
return parsed.href;
|
|
15
|
+
}
|
|
16
|
+
function assertHttpsOrigin(value) {
|
|
17
|
+
const parsed = new URL(value);
|
|
18
|
+
if (parsed.protocol !== 'https:' ||
|
|
19
|
+
parsed.username ||
|
|
20
|
+
parsed.password ||
|
|
21
|
+
(parsed.pathname !== '/' && parsed.pathname !== '') ||
|
|
22
|
+
parsed.search ||
|
|
23
|
+
parsed.hash) {
|
|
24
|
+
throw new Error('aops_external_origin_refused:https_origin_required');
|
|
25
|
+
}
|
|
26
|
+
return parsed.origin;
|
|
27
|
+
}
|
|
28
|
+
function assertSameOriginHttpsUrl(value, expectedOrigin) {
|
|
29
|
+
const origin = assertHttpsOrigin(expectedOrigin);
|
|
30
|
+
const parsed = new URL(value);
|
|
31
|
+
if (parsed.protocol !== 'https:' ||
|
|
32
|
+
parsed.origin !== origin ||
|
|
33
|
+
parsed.username ||
|
|
34
|
+
parsed.password ||
|
|
35
|
+
parsed.hash) {
|
|
36
|
+
throw new Error('aops_external_url_refused:same_origin_https_url_required');
|
|
37
|
+
}
|
|
38
|
+
return parsed.href;
|
|
39
|
+
}
|
|
40
|
+
function resolveOpenInvocation(url, platform) {
|
|
41
|
+
if (platform === 'win32')
|
|
42
|
+
return { command: 'explorer.exe', args: [url] };
|
|
43
|
+
if (platform === 'darwin')
|
|
44
|
+
return { command: 'open', args: [url] };
|
|
45
|
+
return { command: 'xdg-open', args: [url] };
|
|
46
|
+
}
|
|
47
|
+
export function resolveExternalOpenInvocation(value, platform = process.platform) {
|
|
48
|
+
return resolveOpenInvocation(assertLocalHttpUrl(value), platform);
|
|
49
|
+
}
|
|
50
|
+
export function resolveApprovedHttpsOpenInvocation(value, expectedOrigin, platform = process.platform) {
|
|
51
|
+
return resolveOpenInvocation(assertSameOriginHttpsUrl(value, expectedOrigin), platform);
|
|
52
|
+
}
|
|
53
|
+
async function waitForSpawn(child) {
|
|
54
|
+
await new Promise((resolve, reject) => {
|
|
55
|
+
const onSpawn = () => {
|
|
56
|
+
child.off('error', onError);
|
|
57
|
+
resolve();
|
|
58
|
+
};
|
|
59
|
+
const onError = (error) => {
|
|
60
|
+
child.off('spawn', onSpawn);
|
|
61
|
+
reject(error);
|
|
62
|
+
};
|
|
63
|
+
child.once('spawn', onSpawn);
|
|
64
|
+
child.once('error', onError);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
async function observeImmediateOpenFailure(child, timeoutMs) {
|
|
68
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
69
|
+
return { exitCode: child.exitCode, signal: child.signalCode };
|
|
70
|
+
}
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
const finish = (result) => {
|
|
73
|
+
clearTimeout(timer);
|
|
74
|
+
child.off('exit', onExit);
|
|
75
|
+
child.off('error', onError);
|
|
76
|
+
resolve(result);
|
|
77
|
+
};
|
|
78
|
+
const onExit = (exitCode, signal) => finish({ exitCode, signal });
|
|
79
|
+
const onError = (error) => {
|
|
80
|
+
clearTimeout(timer);
|
|
81
|
+
child.off('exit', onExit);
|
|
82
|
+
reject(error);
|
|
83
|
+
};
|
|
84
|
+
const timer = setTimeout(() => finish(null), timeoutMs);
|
|
85
|
+
child.once('exit', onExit);
|
|
86
|
+
child.once('error', onError);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
export async function openExternalUrl(value, runtime = externalOpenRuntime) {
|
|
90
|
+
const invocation = resolveExternalOpenInvocation(value);
|
|
91
|
+
await openInvocation(invocation, runtime);
|
|
92
|
+
}
|
|
93
|
+
export async function openApprovedHttpsUrl(value, expectedOrigin, runtime = externalOpenRuntime) {
|
|
94
|
+
const invocation = resolveApprovedHttpsOpenInvocation(value, expectedOrigin);
|
|
95
|
+
await openInvocation(invocation, runtime);
|
|
96
|
+
}
|
|
97
|
+
async function openInvocation(invocation, runtime) {
|
|
98
|
+
const child = runtime.spawn(invocation.command, invocation.args, {
|
|
99
|
+
detached: true,
|
|
100
|
+
stdio: 'ignore',
|
|
101
|
+
windowsHide: true,
|
|
102
|
+
});
|
|
103
|
+
await waitForSpawn(child);
|
|
104
|
+
const immediateExit = await observeImmediateOpenFailure(child, runtime.handoffTimeoutMs);
|
|
105
|
+
if (immediateExit && immediateExit.exitCode !== 0) {
|
|
106
|
+
throw new Error(`aops_external_open_failed:${immediateExit.exitCode ?? immediateExit.signal ?? 'unknown'}`);
|
|
107
|
+
}
|
|
108
|
+
if (!immediateExit)
|
|
109
|
+
child.unref();
|
|
110
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { assertOfficialCatalogReceiptV1, assertOfficialCatalogSnapshotV1, OFFICIAL_CATALOG_SCOPE_V1, OFFICIAL_CATALOG_TOOL_IDS_V1, OfficialCatalogError, } from './official-catalog.js';
|
|
2
|
+
import { invokeHostedToolWithApiState, unwrapHostedToolResult } from '../utils/agent-gateway.js';
|
|
3
|
+
import { createCliApiClientFromOptions } from '../utils/api.js';
|
|
4
|
+
function isRecord(value) {
|
|
5
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function unwrapData(value) {
|
|
8
|
+
let current = value;
|
|
9
|
+
for (let depth = 0; depth < 4; depth += 1) {
|
|
10
|
+
if (!isRecord(current))
|
|
11
|
+
break;
|
|
12
|
+
if (Object.prototype.hasOwnProperty.call(current, 'response')) {
|
|
13
|
+
current = current.response;
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (Object.prototype.hasOwnProperty.call(current, 'data')) {
|
|
17
|
+
current = current.data;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
return current;
|
|
23
|
+
}
|
|
24
|
+
function remoteError(toolId, error) {
|
|
25
|
+
return new OfficialCatalogError('catalog_adapter_unavailable', `The server does not expose the required official-catalog operation: ${toolId}.`, {
|
|
26
|
+
toolId,
|
|
27
|
+
dependency: 'Agentspace official-catalog composite operation',
|
|
28
|
+
cause: error instanceof Error ? error.message : String(error),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
export function createOfficialCatalogGatewayAdapterV1(invoke) {
|
|
32
|
+
return Object.freeze({
|
|
33
|
+
async inspect() {
|
|
34
|
+
const toolId = OFFICIAL_CATALOG_TOOL_IDS_V1.inspect;
|
|
35
|
+
try {
|
|
36
|
+
const result = unwrapData(await invoke(toolId, { scope: OFFICIAL_CATALOG_SCOPE_V1 }, {
|
|
37
|
+
preview: false,
|
|
38
|
+
apply: false,
|
|
39
|
+
confirm: false,
|
|
40
|
+
}));
|
|
41
|
+
assertOfficialCatalogSnapshotV1(result);
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (error instanceof OfficialCatalogError && error.code !== 'catalog_adapter_unavailable')
|
|
46
|
+
throw error;
|
|
47
|
+
throw remoteError(toolId, error);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
async reconcile(plan, mode) {
|
|
51
|
+
const toolId = OFFICIAL_CATALOG_TOOL_IDS_V1.reconcile;
|
|
52
|
+
try {
|
|
53
|
+
const result = unwrapData(await invoke(toolId, { plan }, {
|
|
54
|
+
preview: mode === 'preview',
|
|
55
|
+
apply: mode === 'apply',
|
|
56
|
+
confirm: false,
|
|
57
|
+
idempotencyKey: plan.idempotencyKey,
|
|
58
|
+
}));
|
|
59
|
+
if (mode === 'preview')
|
|
60
|
+
return result;
|
|
61
|
+
const receipt = result;
|
|
62
|
+
assertOfficialCatalogReceiptV1(receipt, 'reconcile');
|
|
63
|
+
return receipt;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error instanceof OfficialCatalogError && error.code !== 'catalog_adapter_unavailable')
|
|
67
|
+
throw error;
|
|
68
|
+
throw remoteError(toolId, error);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
async rollback(request, mode) {
|
|
72
|
+
const toolId = OFFICIAL_CATALOG_TOOL_IDS_V1.rollback;
|
|
73
|
+
try {
|
|
74
|
+
const result = unwrapData(await invoke(toolId, { request }, {
|
|
75
|
+
preview: mode === 'preview',
|
|
76
|
+
apply: mode === 'apply',
|
|
77
|
+
confirm: mode === 'apply',
|
|
78
|
+
idempotencyKey: request.idempotencyKey,
|
|
79
|
+
}));
|
|
80
|
+
if (mode === 'preview')
|
|
81
|
+
return result;
|
|
82
|
+
const receipt = result;
|
|
83
|
+
assertOfficialCatalogReceiptV1(receipt, 'rollback');
|
|
84
|
+
return receipt;
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
if (error instanceof OfficialCatalogError && error.code !== 'catalog_adapter_unavailable')
|
|
88
|
+
throw error;
|
|
89
|
+
throw remoteError(toolId, error);
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
export async function createHostedOfficialCatalogAdapterV1(options = {}) {
|
|
95
|
+
const apiState = await createCliApiClientFromOptions(options);
|
|
96
|
+
return createOfficialCatalogGatewayAdapterV1(async (toolId, input, envelope) => {
|
|
97
|
+
const payload = await invokeHostedToolWithApiState(apiState, {
|
|
98
|
+
...options,
|
|
99
|
+
toolId,
|
|
100
|
+
input,
|
|
101
|
+
preview: envelope.preview,
|
|
102
|
+
apply: envelope.apply,
|
|
103
|
+
confirm: envelope.confirm,
|
|
104
|
+
idempotencyKey: envelope.idempotencyKey,
|
|
105
|
+
});
|
|
106
|
+
return unwrapHostedToolResult(payload);
|
|
107
|
+
});
|
|
108
|
+
}
|