aidevops 3.32.176 → 3.32.178
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 +1 -1
- package/VERSION +1 -1
- package/aidevops.sh +1 -1
- package/package.json +1 -1
- package/packages/gui-api/src/app.ts +100 -118
- package/setup.sh +1 -1
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ The result: an AI operations platform that manages projects across every busines
|
|
|
60
60
|
[](https://github.com/marcusquinn)
|
|
61
61
|
|
|
62
62
|
<!-- Release & Version Info -->
|
|
63
|
-
[](https://github.com/marcusquinn/aidevops/releases)
|
|
64
64
|
[](https://www.npmjs.com/package/aidevops)
|
|
65
65
|
[](https://github.com/marcusquinn/homebrew-tap)
|
|
66
66
|
[](https://github.com/marcusquinn/aidevops)
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.32.
|
|
1
|
+
3.32.178
|
package/aidevops.sh
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import * as readline from "node:readline";
|
|
3
|
-
import { Hono } from "hono";
|
|
3
|
+
import { type Context, Hono } from "hono";
|
|
4
4
|
import { APP_ACTION_ROUTE_MANIFEST, APP_ACTION_STATUS_ROUTE_MANIFEST, BANNED_ROUTE_PATTERNS, createEnvelope, FILE_EXPLORER_ROUTE_MANIFEST, type GuiAppActionId, type GuiAppActionJobSummary, type GuiPulseWorkerActionId, type GuiPulseWorkerActionJobSummary, PULSE_WORKERS_ACTION_ROUTE_MANIFEST, PULSE_WORKERS_ACTION_STATUS_ROUTE_MANIFEST, STATUS_ROUTE_MANIFEST, TAMBO_PROVIDER_CONFIG, TAMBO_PROXY_ROUTE_MANIFEST, VAULT_STATUS_ROUTE_MANIFEST } from "../../gui-shared/src";
|
|
5
5
|
import { readFileExplorer } from "./file-adapter";
|
|
6
6
|
import { readStatus, readVaultStatus } from "./status-adapter";
|
|
@@ -46,157 +46,139 @@ const pulseWorkerActionJobs = new Map<string, GuiPulseWorkerActionJobSummary>();
|
|
|
46
46
|
export function createGuiApiApp() {
|
|
47
47
|
const app = new Hono();
|
|
48
48
|
|
|
49
|
-
app.get("/api/health", (context) => {
|
|
50
|
-
return context.json(createEnvelope({
|
|
49
|
+
app.get("/api/health", (context) => context.json(createEnvelope({
|
|
51
50
|
operation_id: "capabilities.read",
|
|
52
51
|
source: { surface: "health", authority: "in-process readiness probe", path_refs: [] },
|
|
53
52
|
data: { status: "ok", service: "aidevops-gui-api" },
|
|
54
|
-
}));
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
app.get(STATUS_ROUTE_MANIFEST.route, (context) => {
|
|
58
|
-
return context.json(readStatus());
|
|
59
|
-
});
|
|
53
|
+
})));
|
|
60
54
|
|
|
61
|
-
app.get(
|
|
62
|
-
return context.json(readVaultStatus());
|
|
63
|
-
});
|
|
55
|
+
app.get(STATUS_ROUTE_MANIFEST.route, (context) => context.json(readStatus()));
|
|
64
56
|
|
|
65
|
-
app.get(
|
|
66
|
-
const tenantRef = threadScopeRef(context.req.query("tenant_ref") ?? "local");
|
|
67
|
-
const workspaceRef = threadScopeRef(context.req.query("workspace_ref") ?? "aidevops");
|
|
68
|
-
const sessionRef = context.req.query("session_ref") ?? "conversation:local";
|
|
57
|
+
app.get(VAULT_STATUS_ROUTE_MANIFEST.route, (context) => context.json(readVaultStatus()));
|
|
69
58
|
|
|
70
|
-
|
|
59
|
+
app.get(TAMBO_PROXY_ROUTE_MANIFEST.route, (context) => context.json(createEnvelope({
|
|
71
60
|
operation_id: TAMBO_PROXY_ROUTE_MANIFEST.operation_id,
|
|
72
61
|
source: { surface: "conversations", authority: "server-side Tambo proxy metadata", path_refs: ["packages/gui-shared/src/tambo.ts"] },
|
|
73
62
|
data: {
|
|
74
63
|
...TAMBO_PROVIDER_CONFIG,
|
|
75
|
-
thread_key_ref: `${
|
|
64
|
+
thread_key_ref: `${threadScopeRef(context.req.query("tenant_ref") ?? "local")}:${threadScopeRef(context.req.query("workspace_ref") ?? "aidevops")}:${context.req.query("session_ref") ?? "conversation:local"}`,
|
|
76
65
|
},
|
|
77
66
|
warnings: ["Tambo provider secrets stay server-side; this route exposes component metadata and scoped thread keys only."],
|
|
78
|
-
}));
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
app.post(APP_ACTION_ROUTE_MANIFEST.route, (context) => {
|
|
82
|
-
const appId = context.req.param("appId");
|
|
83
|
-
const action = context.req.param("action") as GuiAppActionId;
|
|
84
|
-
const command = appActionCommands[appId]?.[action];
|
|
85
|
-
|
|
86
|
-
if (command === undefined) {
|
|
87
|
-
return context.json(createEnvelope({
|
|
88
|
-
operation_id: APP_ACTION_ROUTE_MANIFEST.operation_id,
|
|
89
|
-
source: { surface: "apps", authority: "allowlisted local command runner", path_refs: [] },
|
|
90
|
-
data: rejectedJob(appId, action, "No allowlisted command for this app action."),
|
|
91
|
-
errors: ["action_not_allowlisted"],
|
|
92
|
-
}), 400);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const job = startAppActionJob(appId, action, command);
|
|
96
|
-
return context.json(createEnvelope({
|
|
97
|
-
operation_id: APP_ACTION_ROUTE_MANIFEST.operation_id,
|
|
98
|
-
source: { surface: "apps", authority: "allowlisted local command runner", path_refs: ["setup.sh", "aidevops.sh"] },
|
|
99
|
-
data: job,
|
|
100
|
-
warnings: ["Command runs locally in the background. Output is retained in memory for this GUI API process only."],
|
|
101
|
-
}), 202);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
app.get(APP_ACTION_STATUS_ROUTE_MANIFEST.route, (context) => {
|
|
105
|
-
const jobId = context.req.param("jobId");
|
|
106
|
-
const job = appActionJobs.get(jobId);
|
|
107
|
-
if (job === undefined) {
|
|
108
|
-
return context.json(createEnvelope({
|
|
109
|
-
operation_id: APP_ACTION_STATUS_ROUTE_MANIFEST.operation_id,
|
|
110
|
-
source: { surface: "apps", authority: "background job store", path_refs: [] },
|
|
111
|
-
data: rejectedJob("unknown", "install", "Unknown job."),
|
|
112
|
-
errors: ["unknown_job"],
|
|
113
|
-
}), 404);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return context.json(createEnvelope({
|
|
117
|
-
operation_id: APP_ACTION_STATUS_ROUTE_MANIFEST.operation_id,
|
|
118
|
-
source: { surface: "apps", authority: "background job store", path_refs: [] },
|
|
119
|
-
data: job,
|
|
120
|
-
}));
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
app.post(PULSE_WORKERS_ACTION_ROUTE_MANIFEST.route, (context) => {
|
|
124
|
-
const action = context.req.param("action") as GuiPulseWorkerActionId;
|
|
125
|
-
|
|
126
|
-
if (!Object.hasOwn(pulseWorkerActionCommands, action)) {
|
|
127
|
-
return context.json(createEnvelope({
|
|
128
|
-
operation_id: PULSE_WORKERS_ACTION_ROUTE_MANIFEST.operation_id,
|
|
129
|
-
source: { surface: "pulse_workers", authority: "allowlisted local command runner", path_refs: [] },
|
|
130
|
-
data: rejectedPulseWorkerJob(action, "No allowlisted command for this Pulse & Workers action."),
|
|
131
|
-
errors: ["action_not_allowlisted"],
|
|
132
|
-
}), 400);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const actionCommand = pulseWorkerActionCommands[action];
|
|
136
|
-
const job = startPulseWorkerActionJob(action, actionCommand.command, actionCommand.target_ref, actionCommand.audit_ref);
|
|
137
|
-
return context.json(createEnvelope({
|
|
138
|
-
operation_id: PULSE_WORKERS_ACTION_ROUTE_MANIFEST.operation_id,
|
|
139
|
-
source: { surface: "pulse_workers", authority: "allowlisted local command runner", path_refs: [".agents/scripts", "packages/gui-api/src/app.ts"] },
|
|
140
|
-
data: job,
|
|
141
|
-
warnings: ["Command runs locally in the background through an explicit allowlist. Output is redacted and retained in memory for this GUI API process only."],
|
|
142
|
-
}), 202);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
app.get(PULSE_WORKERS_ACTION_STATUS_ROUTE_MANIFEST.route, (context) => {
|
|
146
|
-
const jobId = context.req.param("jobId");
|
|
147
|
-
const job = pulseWorkerActionJobs.get(jobId);
|
|
148
|
-
if (job === undefined) {
|
|
149
|
-
return context.json(createEnvelope({
|
|
150
|
-
operation_id: PULSE_WORKERS_ACTION_STATUS_ROUTE_MANIFEST.operation_id,
|
|
151
|
-
source: { surface: "pulse_workers", authority: "background job store", path_refs: [] },
|
|
152
|
-
data: rejectedPulseWorkerJob("diagnose", "Unknown Pulse & Workers job."),
|
|
153
|
-
errors: ["unknown_job"],
|
|
154
|
-
}), 404);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return context.json(createEnvelope({
|
|
158
|
-
operation_id: PULSE_WORKERS_ACTION_STATUS_ROUTE_MANIFEST.operation_id,
|
|
159
|
-
source: { surface: "pulse_workers", authority: "background job store", path_refs: [] },
|
|
160
|
-
data: job,
|
|
161
|
-
}));
|
|
162
|
-
});
|
|
67
|
+
})));
|
|
163
68
|
|
|
164
|
-
app.
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const status = response.ok ? 200 : response.errors.includes("unknown_file_root") ? 404 : 400;
|
|
69
|
+
app.post(APP_ACTION_ROUTE_MANIFEST.route, handleAppAction);
|
|
70
|
+
app.get(APP_ACTION_STATUS_ROUTE_MANIFEST.route, handleAppActionStatus);
|
|
71
|
+
app.post(PULSE_WORKERS_ACTION_ROUTE_MANIFEST.route, handlePulseWorkerAction);
|
|
72
|
+
app.get(PULSE_WORKERS_ACTION_STATUS_ROUTE_MANIFEST.route, handlePulseWorkerActionStatus);
|
|
169
73
|
|
|
170
|
-
|
|
171
|
-
|
|
74
|
+
app.get(FILE_EXPLORER_ROUTE_MANIFEST.route, (context) => context.json(
|
|
75
|
+
...fileExplorerResult(context.req.param("root"), context.req.query("path") ?? ""),
|
|
76
|
+
));
|
|
172
77
|
|
|
173
78
|
for (const route of BANNED_ROUTE_PATTERNS) {
|
|
174
|
-
app.post(route, (context) =>
|
|
175
|
-
return context.json(
|
|
79
|
+
app.post(route, (context) => context.json(
|
|
176
80
|
{
|
|
177
81
|
ok: false,
|
|
178
82
|
operation_id: "capabilities.read",
|
|
179
83
|
errors: ["write_actions_disabled"],
|
|
180
84
|
},
|
|
181
85
|
405,
|
|
182
|
-
);
|
|
183
|
-
});
|
|
86
|
+
));
|
|
184
87
|
}
|
|
185
88
|
|
|
186
|
-
app.notFound((context) =>
|
|
187
|
-
return context.json(
|
|
89
|
+
app.notFound((context) => context.json(
|
|
188
90
|
{
|
|
189
91
|
ok: false,
|
|
190
92
|
operation_id: "capabilities.read",
|
|
191
93
|
errors: ["unknown_route"],
|
|
192
94
|
},
|
|
193
95
|
404,
|
|
194
|
-
);
|
|
195
|
-
});
|
|
96
|
+
));
|
|
196
97
|
|
|
197
98
|
return app;
|
|
198
99
|
}
|
|
199
100
|
|
|
101
|
+
function handleAppAction(context: Context) {
|
|
102
|
+
const appId = context.req.param("appId");
|
|
103
|
+
const action = context.req.param("action") as GuiAppActionId;
|
|
104
|
+
const command = appActionCommands[appId]?.[action];
|
|
105
|
+
if (command === undefined) {
|
|
106
|
+
return context.json(createEnvelope({
|
|
107
|
+
operation_id: APP_ACTION_ROUTE_MANIFEST.operation_id,
|
|
108
|
+
source: { surface: "apps", authority: "allowlisted local command runner", path_refs: [] },
|
|
109
|
+
data: rejectedJob(appId, action, "No allowlisted command for this app action."),
|
|
110
|
+
errors: ["action_not_allowlisted"],
|
|
111
|
+
}), 400);
|
|
112
|
+
}
|
|
113
|
+
const job = startAppActionJob(appId, action, command);
|
|
114
|
+
return context.json(createEnvelope({
|
|
115
|
+
operation_id: APP_ACTION_ROUTE_MANIFEST.operation_id,
|
|
116
|
+
source: { surface: "apps", authority: "allowlisted local command runner", path_refs: ["setup.sh", "aidevops.sh"] },
|
|
117
|
+
data: job,
|
|
118
|
+
warnings: ["Command runs locally in the background. Output is retained in memory for this GUI API process only."],
|
|
119
|
+
}), 202);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function handleAppActionStatus(context: Context) {
|
|
123
|
+
const job = appActionJobs.get(context.req.param("jobId"));
|
|
124
|
+
if (job === undefined) {
|
|
125
|
+
return context.json(createEnvelope({
|
|
126
|
+
operation_id: APP_ACTION_STATUS_ROUTE_MANIFEST.operation_id,
|
|
127
|
+
source: { surface: "apps", authority: "background job store", path_refs: [] },
|
|
128
|
+
data: rejectedJob("unknown", "install", "Unknown job."),
|
|
129
|
+
errors: ["unknown_job"],
|
|
130
|
+
}), 404);
|
|
131
|
+
}
|
|
132
|
+
return context.json(createEnvelope({
|
|
133
|
+
operation_id: APP_ACTION_STATUS_ROUTE_MANIFEST.operation_id,
|
|
134
|
+
source: { surface: "apps", authority: "background job store", path_refs: [] },
|
|
135
|
+
data: job,
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function handlePulseWorkerAction(context: Context) {
|
|
140
|
+
const action = context.req.param("action") as GuiPulseWorkerActionId;
|
|
141
|
+
if (!Object.hasOwn(pulseWorkerActionCommands, action)) {
|
|
142
|
+
return context.json(createEnvelope({
|
|
143
|
+
operation_id: PULSE_WORKERS_ACTION_ROUTE_MANIFEST.operation_id,
|
|
144
|
+
source: { surface: "pulse_workers", authority: "allowlisted local command runner", path_refs: [] },
|
|
145
|
+
data: rejectedPulseWorkerJob(action, "No allowlisted command for this Pulse & Workers action."),
|
|
146
|
+
errors: ["action_not_allowlisted"],
|
|
147
|
+
}), 400);
|
|
148
|
+
}
|
|
149
|
+
const actionCommand = pulseWorkerActionCommands[action];
|
|
150
|
+
const job = startPulseWorkerActionJob(action, actionCommand.command, actionCommand.target_ref, actionCommand.audit_ref);
|
|
151
|
+
return context.json(createEnvelope({
|
|
152
|
+
operation_id: PULSE_WORKERS_ACTION_ROUTE_MANIFEST.operation_id,
|
|
153
|
+
source: { surface: "pulse_workers", authority: "allowlisted local command runner", path_refs: [".agents/scripts", "packages/gui-api/src/app.ts"] },
|
|
154
|
+
data: job,
|
|
155
|
+
warnings: ["Command runs locally in the background through an explicit allowlist. Output is redacted and retained in memory for this GUI API process only."],
|
|
156
|
+
}), 202);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function handlePulseWorkerActionStatus(context: Context) {
|
|
160
|
+
const job = pulseWorkerActionJobs.get(context.req.param("jobId"));
|
|
161
|
+
if (job === undefined) {
|
|
162
|
+
return context.json(createEnvelope({
|
|
163
|
+
operation_id: PULSE_WORKERS_ACTION_STATUS_ROUTE_MANIFEST.operation_id,
|
|
164
|
+
source: { surface: "pulse_workers", authority: "background job store", path_refs: [] },
|
|
165
|
+
data: rejectedPulseWorkerJob("diagnose", "Unknown Pulse & Workers job."),
|
|
166
|
+
errors: ["unknown_job"],
|
|
167
|
+
}), 404);
|
|
168
|
+
}
|
|
169
|
+
return context.json(createEnvelope({
|
|
170
|
+
operation_id: PULSE_WORKERS_ACTION_STATUS_ROUTE_MANIFEST.operation_id,
|
|
171
|
+
source: { surface: "pulse_workers", authority: "background job store", path_refs: [] },
|
|
172
|
+
data: job,
|
|
173
|
+
}));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function fileExplorerResult(root: string, path: string) {
|
|
177
|
+
const response = readFileExplorer(root, path);
|
|
178
|
+
const status = response.ok ? 200 : response.errors.includes("unknown_file_root") ? 404 : 400;
|
|
179
|
+
return [response, status] as const;
|
|
180
|
+
}
|
|
181
|
+
|
|
200
182
|
function startAppActionJob(appId: string, action: GuiAppActionId, command: string[]): GuiAppActionJobSummary {
|
|
201
183
|
const now = new Date().toISOString();
|
|
202
184
|
const redactLine = createOutputLineRedactor();
|
package/setup.sh
CHANGED
|
@@ -17,7 +17,7 @@ fi
|
|
|
17
17
|
# AI Assistant Server Access Framework Setup Script
|
|
18
18
|
# Helps developers set up the framework for their infrastructure
|
|
19
19
|
#
|
|
20
|
-
# Version: 3.32.
|
|
20
|
+
# Version: 3.32.178
|
|
21
21
|
#
|
|
22
22
|
# Quick Install:
|
|
23
23
|
# npm install -g aidevops && aidevops update (recommended)
|