@action-llama/action-llama 0.21.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/build-info.json +1 -1
  2. package/dist/cloud/gcp/artifact-registry-api.d.ts +26 -0
  3. package/dist/cloud/gcp/artifact-registry-api.d.ts.map +1 -0
  4. package/dist/cloud/gcp/artifact-registry-api.js +64 -0
  5. package/dist/cloud/gcp/artifact-registry-api.js.map +1 -0
  6. package/dist/cloud/gcp/auth.d.ts +25 -0
  7. package/dist/cloud/gcp/auth.d.ts.map +1 -0
  8. package/dist/cloud/gcp/auth.js +73 -0
  9. package/dist/cloud/gcp/auth.js.map +1 -0
  10. package/dist/cloud/gcp/cloud-run-api.d.ts +96 -0
  11. package/dist/cloud/gcp/cloud-run-api.d.ts.map +1 -0
  12. package/dist/cloud/gcp/cloud-run-api.js +86 -0
  13. package/dist/cloud/gcp/cloud-run-api.js.map +1 -0
  14. package/dist/cloud/gcp/logging-api.d.ts +31 -0
  15. package/dist/cloud/gcp/logging-api.d.ts.map +1 -0
  16. package/dist/cloud/gcp/logging-api.js +44 -0
  17. package/dist/cloud/gcp/logging-api.js.map +1 -0
  18. package/dist/cloud/gcp/secret-manager-api.d.ts +10 -0
  19. package/dist/cloud/gcp/secret-manager-api.d.ts.map +1 -0
  20. package/dist/cloud/gcp/secret-manager-api.js +33 -0
  21. package/dist/cloud/gcp/secret-manager-api.js.map +1 -0
  22. package/dist/control/routes/dashboard.d.ts.map +1 -1
  23. package/dist/control/routes/dashboard.js +21 -2
  24. package/dist/control/routes/dashboard.js.map +1 -1
  25. package/dist/control/routes/stats.d.ts.map +1 -1
  26. package/dist/control/routes/stats.js +3 -2
  27. package/dist/control/routes/stats.js.map +1 -1
  28. package/dist/credentials/builtins/gcp-service-account.d.ts +4 -0
  29. package/dist/credentials/builtins/gcp-service-account.d.ts.map +1 -0
  30. package/dist/credentials/builtins/gcp-service-account.js +38 -0
  31. package/dist/credentials/builtins/gcp-service-account.js.map +1 -0
  32. package/dist/credentials/builtins/index.d.ts.map +1 -1
  33. package/dist/credentials/builtins/index.js +2 -0
  34. package/dist/credentials/builtins/index.js.map +1 -1
  35. package/dist/docker/cloud-run-runtime.d.ts +48 -0
  36. package/dist/docker/cloud-run-runtime.d.ts.map +1 -0
  37. package/dist/docker/cloud-run-runtime.js +490 -0
  38. package/dist/docker/cloud-run-runtime.js.map +1 -0
  39. package/dist/docker/host-user-runtime.d.ts.map +1 -1
  40. package/dist/docker/host-user-runtime.js +22 -14
  41. package/dist/docker/host-user-runtime.js.map +1 -1
  42. package/dist/docker/providers/index.d.ts +4 -0
  43. package/dist/docker/providers/index.d.ts.map +1 -1
  44. package/dist/docker/providers/index.js +38 -0
  45. package/dist/docker/providers/index.js.map +1 -1
  46. package/dist/docker/runtime.d.ts +7 -0
  47. package/dist/docker/runtime.d.ts.map +1 -1
  48. package/dist/docker/runtime.js.map +1 -1
  49. package/dist/execution/routes/locks.d.ts.map +1 -1
  50. package/dist/execution/routes/locks.js +3 -18
  51. package/dist/execution/routes/locks.js.map +1 -1
  52. package/dist/frontend/assets/index-BOXUAoMg.js +13 -0
  53. package/dist/frontend/assets/index-BPbM5Azj.css +2 -0
  54. package/dist/frontend/index.html +2 -2
  55. package/dist/gateway/frontend.d.ts.map +1 -1
  56. package/dist/gateway/frontend.js +1 -0
  57. package/dist/gateway/frontend.js.map +1 -1
  58. package/dist/scheduler/index.d.ts.map +1 -1
  59. package/dist/scheduler/index.js +2 -0
  60. package/dist/scheduler/index.js.map +1 -1
  61. package/dist/scheduler/watcher.d.ts.map +1 -1
  62. package/dist/scheduler/watcher.js +3 -0
  63. package/dist/scheduler/watcher.js.map +1 -1
  64. package/dist/shared/config/types.d.ts +12 -1
  65. package/dist/shared/config/types.d.ts.map +1 -1
  66. package/dist/tui/status-tracker.d.ts +8 -0
  67. package/dist/tui/status-tracker.d.ts.map +1 -1
  68. package/dist/tui/status-tracker.js +35 -0
  69. package/dist/tui/status-tracker.js.map +1 -1
  70. package/docker/bin/al-subagent +1 -2
  71. package/docker/bin/al-subagent-wait +1 -1
  72. package/package.json +1 -1
  73. package/dist/frontend/assets/index-CtDub1yn.css +0 -2
  74. package/dist/frontend/assets/index-Dp0WUSmO.js +0 -13
@@ -1 +1 @@
1
- {"gitSha":"871f73bc"}
1
+ {"gitSha":"b176a4d5"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Artifact Registry API client (for image cleanup).
3
+ * Plain fetch() wrapper — no SDK dependency.
4
+ */
5
+ import type { GcpAuth } from "./auth.js";
6
+ export interface DockerImage {
7
+ name: string;
8
+ uri: string;
9
+ tags: string[];
10
+ imageSizeBytes?: string;
11
+ uploadTime?: string;
12
+ updateTime?: string;
13
+ buildTime?: string;
14
+ mediaType?: string;
15
+ }
16
+ export declare function listDockerImages(auth: GcpAuth, project: string, region: string, repo: string, pageToken?: string): Promise<{
17
+ dockerImages: DockerImage[];
18
+ nextPageToken?: string;
19
+ }>;
20
+ export declare function deleteDockerImage(auth: GcpAuth, imageName: string): Promise<void>;
21
+ /**
22
+ * Keep only the most recent `keepCount` images for the given image name.
23
+ * Deletes all older images.
24
+ */
25
+ export declare function cleanupOldImages(auth: GcpAuth, project: string, region: string, repo: string, imageName: string, keepCount?: number): Promise<void>;
26
+ //# sourceMappingURL=artifact-registry-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-registry-api.d.ts","sourceRoot":"","sources":["../../../src/cloud/gcp/artifact-registry-api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,YAAY,EAAE,WAAW,EAAE,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAQlE;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAGf;AAqBD;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,SAAS,SAAI,GACZ,OAAO,CAAC,IAAI,CAAC,CA6Bf"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Artifact Registry API client (for image cleanup).
3
+ * Plain fetch() wrapper — no SDK dependency.
4
+ */
5
+ import { gcpFetch } from "./cloud-run-api.js";
6
+ const BASE_URL = "https://artifactregistry.googleapis.com/v1";
7
+ export async function listDockerImages(auth, project, region, repo, pageToken) {
8
+ let url = `${BASE_URL}/projects/${project}/locations/${region}/repositories/${repo}/dockerImages`;
9
+ if (pageToken)
10
+ url += `?pageToken=${encodeURIComponent(pageToken)}`;
11
+ const data = await gcpFetch(auth, url);
12
+ return {
13
+ dockerImages: data?.dockerImages ?? [],
14
+ nextPageToken: data?.nextPageToken,
15
+ };
16
+ }
17
+ export async function deleteDockerImage(auth, imageName) {
18
+ // imageName is the full resource path from the list response
19
+ await gcpFetch(auth, `${BASE_URL}/${imageName}`, { method: "DELETE" });
20
+ }
21
+ /**
22
+ * Fetch ALL docker images across pages.
23
+ */
24
+ async function listAllDockerImages(auth, project, region, repo) {
25
+ const all = [];
26
+ let pageToken;
27
+ do {
28
+ const resp = await listDockerImages(auth, project, region, repo, pageToken);
29
+ all.push(...resp.dockerImages);
30
+ pageToken = resp.nextPageToken;
31
+ } while (pageToken);
32
+ return all;
33
+ }
34
+ /**
35
+ * Keep only the most recent `keepCount` images for the given image name.
36
+ * Deletes all older images.
37
+ */
38
+ export async function cleanupOldImages(auth, project, region, repo, imageName, keepCount = 3) {
39
+ const all = await listAllDockerImages(auth, project, region, repo);
40
+ // Filter to images matching the given name (base name without tag)
41
+ const registryBase = `${region}-docker.pkg.dev/${project}/${repo}/${imageName}`;
42
+ const matching = all.filter((img) => img.uri.startsWith(registryBase + "@") || img.uri.startsWith(registryBase + ":"));
43
+ // Sort by upload time descending (newest first)
44
+ matching.sort((a, b) => {
45
+ const ta = a.uploadTime ?? a.updateTime ?? "";
46
+ const tb = b.uploadTime ?? b.updateTime ?? "";
47
+ return tb.localeCompare(ta);
48
+ });
49
+ // Delete all beyond keepCount
50
+ const toDelete = matching.slice(keepCount);
51
+ for (const img of toDelete) {
52
+ // The name field is already the full resource path
53
+ const resourcePath = img.name.startsWith("projects/")
54
+ ? img.name
55
+ : img.name;
56
+ try {
57
+ await deleteDockerImage(auth, resourcePath);
58
+ }
59
+ catch {
60
+ // Best effort — don't fail the push if cleanup fails
61
+ }
62
+ }
63
+ }
64
+ //# sourceMappingURL=artifact-registry-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-registry-api.js","sourceRoot":"","sources":["../../../src/cloud/gcp/artifact-registry-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * GCP service account JWT authentication.
3
+ * Uses only Node.js built-in `crypto` — no external dependencies.
4
+ */
5
+ export interface ServiceAccountKey {
6
+ type: string;
7
+ project_id: string;
8
+ private_key_id: string;
9
+ private_key: string;
10
+ client_email: string;
11
+ client_id: string;
12
+ auth_uri: string;
13
+ token_uri: string;
14
+ }
15
+ export declare function parseServiceAccountKey(json: string): ServiceAccountKey;
16
+ export declare class GcpAuth {
17
+ private key;
18
+ private cached;
19
+ constructor(key: ServiceAccountKey);
20
+ /**
21
+ * Get a valid access token (cached, auto-refreshed 5 min before expiry).
22
+ */
23
+ getAccessToken(): Promise<string>;
24
+ }
25
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/cloud/gcp/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAOD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CActE;AAOD,qBAAa,OAAO;IAClB,OAAO,CAAC,GAAG,CAAoB;IAC/B,OAAO,CAAC,MAAM,CAA4B;gBAE9B,GAAG,EAAE,iBAAiB;IAIlC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;CA8CxC"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * GCP service account JWT authentication.
3
+ * Uses only Node.js built-in `crypto` — no external dependencies.
4
+ */
5
+ import { createSign } from "crypto";
6
+ export function parseServiceAccountKey(json) {
7
+ let key;
8
+ try {
9
+ key = JSON.parse(json);
10
+ }
11
+ catch {
12
+ throw new Error("Invalid JSON — expected a service account key file");
13
+ }
14
+ if (key.type !== "service_account") {
15
+ throw new Error('JSON key type must be "service_account"');
16
+ }
17
+ if (!key.private_key || !key.client_email || !key.project_id) {
18
+ throw new Error("JSON key missing required fields (private_key, client_email, project_id)");
19
+ }
20
+ return key;
21
+ }
22
+ function base64url(data) {
23
+ const buf = typeof data === "string" ? Buffer.from(data, "utf-8") : data;
24
+ return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
25
+ }
26
+ export class GcpAuth {
27
+ key;
28
+ cached = null;
29
+ constructor(key) {
30
+ this.key = key;
31
+ }
32
+ /**
33
+ * Get a valid access token (cached, auto-refreshed 5 min before expiry).
34
+ */
35
+ async getAccessToken() {
36
+ const now = Date.now();
37
+ // Return cached token if still valid (with 5-minute buffer)
38
+ if (this.cached && this.cached.expiresAt - now > 5 * 60 * 1000) {
39
+ return this.cached.accessToken;
40
+ }
41
+ const nowSec = Math.floor(now / 1000);
42
+ const expSec = nowSec + 3600;
43
+ const header = base64url(JSON.stringify({ alg: "RS256", typ: "JWT" }));
44
+ const payload = base64url(JSON.stringify({
45
+ iss: this.key.client_email,
46
+ scope: "https://www.googleapis.com/auth/cloud-platform",
47
+ aud: "https://oauth2.googleapis.com/token",
48
+ iat: nowSec,
49
+ exp: expSec,
50
+ }));
51
+ const signingInput = `${header}.${payload}`;
52
+ const signer = createSign("RSA-SHA256");
53
+ signer.update(signingInput);
54
+ const signature = base64url(signer.sign(this.key.private_key));
55
+ const jwt = `${signingInput}.${signature}`;
56
+ const res = await fetch("https://oauth2.googleapis.com/token", {
57
+ method: "POST",
58
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
59
+ body: `grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=${jwt}`,
60
+ });
61
+ if (!res.ok) {
62
+ const body = await res.text().catch(() => "");
63
+ throw new Error(`GCP token exchange failed (HTTP ${res.status}): ${body}`);
64
+ }
65
+ const data = await res.json();
66
+ this.cached = {
67
+ accessToken: data.access_token,
68
+ expiresAt: now + data.expires_in * 1000,
69
+ };
70
+ return this.cached.accessToken;
71
+ }
72
+ }
73
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/cloud/gcp/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Cloud Run Jobs v2 REST API client.
3
+ * Plain fetch() wrapper — no SDK dependency.
4
+ */
5
+ import type { GcpAuth } from "./auth.js";
6
+ export declare class GcpApiError extends Error {
7
+ statusCode: number;
8
+ constructor(statusCode: number, message: string);
9
+ }
10
+ export declare function gcpFetch(auth: GcpAuth, url: string, options?: RequestInit): Promise<any>;
11
+ export interface CloudRunEnvVar {
12
+ name: string;
13
+ value?: string;
14
+ }
15
+ export interface CloudRunVolumeMount {
16
+ name: string;
17
+ mountPath: string;
18
+ }
19
+ export interface CloudRunContainer {
20
+ image: string;
21
+ env?: CloudRunEnvVar[];
22
+ volumeMounts?: CloudRunVolumeMount[];
23
+ resources?: {
24
+ limits?: {
25
+ cpu?: string;
26
+ memory?: string;
27
+ };
28
+ };
29
+ }
30
+ export interface CloudRunVolume {
31
+ name: string;
32
+ secret?: {
33
+ secret: string;
34
+ items: Array<{
35
+ version: string;
36
+ path: string;
37
+ mode?: number;
38
+ }>;
39
+ };
40
+ }
41
+ export interface CloudRunTaskTemplate {
42
+ containers: CloudRunContainer[];
43
+ volumes?: CloudRunVolume[];
44
+ maxRetries?: number;
45
+ timeout?: string;
46
+ serviceAccount?: string;
47
+ }
48
+ export interface CloudRunJobTemplate {
49
+ template: CloudRunTaskTemplate;
50
+ labels?: Record<string, string>;
51
+ annotations?: Record<string, string>;
52
+ }
53
+ export interface CloudRunJob {
54
+ name: string;
55
+ uid: string;
56
+ createTime: string;
57
+ updateTime: string;
58
+ template: CloudRunJobTemplate;
59
+ labels?: Record<string, string>;
60
+ annotations?: Record<string, string>;
61
+ }
62
+ export interface CloudRunExecution {
63
+ name: string;
64
+ uid: string;
65
+ createTime: string;
66
+ completionTime?: string;
67
+ conditions?: Array<{
68
+ type: string;
69
+ state: string;
70
+ message?: string;
71
+ }>;
72
+ taskCount?: number;
73
+ completedCount?: number;
74
+ failedCount?: number;
75
+ }
76
+ export interface CloudRunOperation {
77
+ name: string;
78
+ done?: boolean;
79
+ response?: any;
80
+ error?: {
81
+ code: number;
82
+ message: string;
83
+ };
84
+ }
85
+ export declare function createJob(auth: GcpAuth, project: string, region: string, jobId: string, template: CloudRunJobTemplate): Promise<CloudRunOperation>;
86
+ export declare function getJob(auth: GcpAuth, project: string, region: string, jobId: string): Promise<CloudRunJob>;
87
+ export declare function deleteJob(auth: GcpAuth, project: string, region: string, jobId: string): Promise<CloudRunOperation>;
88
+ export declare function runJob(auth: GcpAuth, project: string, region: string, jobId: string, overrides?: Record<string, unknown>): Promise<CloudRunOperation>;
89
+ export declare function getExecution(auth: GcpAuth, _project: string, _region: string, executionName: string): Promise<CloudRunExecution>;
90
+ export declare function listExecutions(auth: GcpAuth, project: string, region: string, jobId: string): Promise<CloudRunExecution[]>;
91
+ export declare function listJobs(auth: GcpAuth, project: string, region: string): Promise<CloudRunJob[]>;
92
+ /**
93
+ * Poll an execution until it completes or times out.
94
+ */
95
+ export declare function pollExecutionUntilDone(auth: GcpAuth, project: string, region: string, executionName: string, timeoutMs: number, pollIntervalMs?: number): Promise<CloudRunExecution>;
96
+ //# sourceMappingURL=cloud-run-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-run-api.d.ts","sourceRoot":"","sources":["../../../src/cloud/gcp/cloud-run-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Cloud Run Jobs v2 REST API client.
3
+ * Plain fetch() wrapper — no SDK dependency.
4
+ */
5
+ const BASE_URL = "https://run.googleapis.com/v2";
6
+ export class GcpApiError extends Error {
7
+ statusCode;
8
+ constructor(statusCode, message) {
9
+ super(message);
10
+ this.statusCode = statusCode;
11
+ this.name = "GcpApiError";
12
+ }
13
+ }
14
+ export async function gcpFetch(auth, url, options = {}) {
15
+ const token = await auth.getAccessToken();
16
+ const res = await fetch(url, {
17
+ ...options,
18
+ headers: {
19
+ Authorization: `Bearer ${token}`,
20
+ "Content-Type": "application/json",
21
+ ...options.headers,
22
+ },
23
+ });
24
+ if (!res.ok) {
25
+ const body = await res.text().catch(() => "");
26
+ throw new GcpApiError(res.status, `GCP API ${url} failed (HTTP ${res.status}): ${body}`);
27
+ }
28
+ const text = await res.text();
29
+ return text ? JSON.parse(text) : null;
30
+ }
31
+ function jobPath(project, region, jobId) {
32
+ return `${BASE_URL}/projects/${project}/locations/${region}/jobs/${jobId}`;
33
+ }
34
+ export async function createJob(auth, project, region, jobId, template) {
35
+ const url = `${BASE_URL}/projects/${project}/locations/${region}/jobs?jobId=${encodeURIComponent(jobId)}`;
36
+ return gcpFetch(auth, url, {
37
+ method: "POST",
38
+ body: JSON.stringify({ template }),
39
+ });
40
+ }
41
+ export async function getJob(auth, project, region, jobId) {
42
+ return gcpFetch(auth, jobPath(project, region, jobId));
43
+ }
44
+ export async function deleteJob(auth, project, region, jobId) {
45
+ return gcpFetch(auth, jobPath(project, region, jobId), { method: "DELETE" });
46
+ }
47
+ export async function runJob(auth, project, region, jobId, overrides) {
48
+ const url = `${jobPath(project, region, jobId)}:run`;
49
+ return gcpFetch(auth, url, {
50
+ method: "POST",
51
+ body: JSON.stringify(overrides ?? {}),
52
+ });
53
+ }
54
+ export async function getExecution(auth, _project, _region, executionName) {
55
+ return gcpFetch(auth, `${BASE_URL}/${executionName}`);
56
+ }
57
+ export async function listExecutions(auth, project, region, jobId) {
58
+ const url = `${jobPath(project, region, jobId)}/executions`;
59
+ const data = await gcpFetch(auth, url);
60
+ return data?.executions ?? [];
61
+ }
62
+ export async function listJobs(auth, project, region) {
63
+ const url = `${BASE_URL}/projects/${project}/locations/${region}/jobs`;
64
+ const data = await gcpFetch(auth, url);
65
+ return data?.jobs ?? [];
66
+ }
67
+ /**
68
+ * Poll an execution until it completes or times out.
69
+ */
70
+ export async function pollExecutionUntilDone(auth, project, region, executionName, timeoutMs, pollIntervalMs = 5000) {
71
+ const deadline = Date.now() + timeoutMs;
72
+ while (Date.now() < deadline) {
73
+ const exec = await getExecution(auth, project, region, executionName);
74
+ if (exec.completionTime) {
75
+ return exec;
76
+ }
77
+ // Check if failed even without completionTime
78
+ const completed = exec.conditions?.find((c) => c.type === "Completed");
79
+ if (completed && completed.state !== "CONDITION_PENDING" && completed.state !== "CONDITION_RECONCILING") {
80
+ return exec;
81
+ }
82
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
83
+ }
84
+ throw new Error(`Execution ${executionName} timed out after ${timeoutMs}ms`);
85
+ }
86
+ //# sourceMappingURL=cloud-run-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-run-api.js","sourceRoot":"","sources":["../../../src/cloud/gcp/cloud-run-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Cloud Logging v2 REST API client.
3
+ * Plain fetch() wrapper — no SDK dependency.
4
+ */
5
+ import type { GcpAuth } from "./auth.js";
6
+ export interface LogEntry {
7
+ logName?: string;
8
+ textPayload?: string;
9
+ jsonPayload?: Record<string, any>;
10
+ timestamp?: string;
11
+ insertId?: string;
12
+ severity?: string;
13
+ resource?: {
14
+ type: string;
15
+ labels: Record<string, string>;
16
+ };
17
+ }
18
+ export interface ListLogEntriesResponse {
19
+ entries?: LogEntry[];
20
+ nextPageToken?: string;
21
+ }
22
+ export declare function listLogEntries(auth: GcpAuth, project: string, filter: string, pageSize?: number, orderBy?: string, pageToken?: string): Promise<ListLogEntriesResponse>;
23
+ /**
24
+ * Build a Cloud Logging filter for Cloud Run Job logs.
25
+ */
26
+ export declare function buildJobLogFilter(region: string, jobId: string, afterTimestamp?: string): string;
27
+ /**
28
+ * Extract the text content from a log entry.
29
+ */
30
+ export declare function extractLogText(entry: LogEntry): string;
31
+ //# sourceMappingURL=logging-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logging-api.d.ts","sourceRoot":"","sources":["../../../src/cloud/gcp/logging-api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,MAAM,WAAW,QAAQ;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE;QACT,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAChC,CAAC;CACH;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,sBAAsB,CAAC,CAcjC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,CAMR;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAItD"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Cloud Logging v2 REST API client.
3
+ * Plain fetch() wrapper — no SDK dependency.
4
+ */
5
+ import { gcpFetch } from "./cloud-run-api.js";
6
+ const BASE_URL = "https://logging.googleapis.com/v2";
7
+ export async function listLogEntries(auth, project, filter, pageSize, orderBy, pageToken) {
8
+ const url = `${BASE_URL}/entries:list`;
9
+ const body = {
10
+ resourceNames: [`projects/${project}`],
11
+ filter,
12
+ };
13
+ if (pageSize)
14
+ body.pageSize = pageSize;
15
+ if (orderBy)
16
+ body.orderBy = orderBy;
17
+ if (pageToken)
18
+ body.pageToken = pageToken;
19
+ return gcpFetch(auth, url, {
20
+ method: "POST",
21
+ body: JSON.stringify(body),
22
+ });
23
+ }
24
+ /**
25
+ * Build a Cloud Logging filter for Cloud Run Job logs.
26
+ */
27
+ export function buildJobLogFilter(region, jobId, afterTimestamp) {
28
+ let filter = `resource.type="cloud_run_job" AND resource.labels.job_name="${jobId}" AND resource.labels.location="${region}"`;
29
+ if (afterTimestamp) {
30
+ filter += ` AND timestamp>"${afterTimestamp}"`;
31
+ }
32
+ return filter;
33
+ }
34
+ /**
35
+ * Extract the text content from a log entry.
36
+ */
37
+ export function extractLogText(entry) {
38
+ if (entry.textPayload)
39
+ return entry.textPayload;
40
+ if (entry.jsonPayload)
41
+ return JSON.stringify(entry.jsonPayload);
42
+ return "";
43
+ }
44
+ //# sourceMappingURL=logging-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logging-api.js","sourceRoot":"","sources":["../../../src/cloud/gcp/logging-api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,MAAM,QAAQ,GAAG,mCAAmC,CAAC;AAoBrD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAa,EACb,OAAe,EACf,MAAc,EACd,QAAiB,EACjB,OAAgB,EAChB,SAAkB;IAElB,MAAM,GAAG,GAAG,GAAG,QAAQ,eAAe,CAAC;IACvC,MAAM,IAAI,GAAwB;QAChC,aAAa,EAAE,CAAC,YAAY,OAAO,EAAE,CAAC;QACtC,MAAM;KACP,CAAC;IACF,IAAI,QAAQ;QAAE,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IACvC,IAAI,OAAO;QAAE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACpC,IAAI,SAAS;QAAE,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAE1C,OAAO,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE;QACzB,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAc,EACd,KAAa,EACb,cAAuB;IAEvB,IAAI,MAAM,GAAG,+DAA+D,KAAK,mCAAmC,MAAM,GAAG,CAAC;IAC9H,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,IAAI,mBAAmB,cAAc,GAAG,CAAC;IACjD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,KAAe;IAC5C,IAAI,KAAK,CAAC,WAAW;QAAE,OAAO,KAAK,CAAC,WAAW,CAAC;IAChD,IAAI,KAAK,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAChE,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Secret Manager v1 REST API client.
3
+ * Plain fetch() wrapper — no SDK dependency.
4
+ */
5
+ import type { GcpAuth } from "./auth.js";
6
+ export declare function createSecret(auth: GcpAuth, project: string, secretId: string): Promise<any>;
7
+ export declare function addSecretVersion(auth: GcpAuth, project: string, secretId: string, payload: string): Promise<any>;
8
+ export declare function deleteSecret(auth: GcpAuth, project: string, secretId: string): Promise<void>;
9
+ export declare function accessSecretVersion(auth: GcpAuth, project: string, secretId: string, version?: string): Promise<string>;
10
+ //# sourceMappingURL=secret-manager-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-manager-api.d.ts","sourceRoot":"","sources":["../../../src/cloud/gcp/secret-manager-api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQzC,wBAAsB,YAAY,CAChC,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,GAAG,CAAC,CAMd;AAED,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,GAAG,CAAC,CAOd;AAED,wBAAsB,YAAY,CAChC,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,SAAW,GACjB,OAAO,CAAC,MAAM,CAAC,CAIjB"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Secret Manager v1 REST API client.
3
+ * Plain fetch() wrapper — no SDK dependency.
4
+ */
5
+ import { gcpFetch } from "./cloud-run-api.js";
6
+ const BASE_URL = "https://secretmanager.googleapis.com/v1";
7
+ function secretPath(project, secretId) {
8
+ return `${BASE_URL}/projects/${project}/secrets/${secretId}`;
9
+ }
10
+ export async function createSecret(auth, project, secretId) {
11
+ const url = `${BASE_URL}/projects/${project}/secrets?secretId=${encodeURIComponent(secretId)}`;
12
+ return gcpFetch(auth, url, {
13
+ method: "POST",
14
+ body: JSON.stringify({ replication: { automatic: {} } }),
15
+ });
16
+ }
17
+ export async function addSecretVersion(auth, project, secretId, payload) {
18
+ const url = `${secretPath(project, secretId)}:addVersion`;
19
+ const data = Buffer.from(payload, "utf-8").toString("base64");
20
+ return gcpFetch(auth, url, {
21
+ method: "POST",
22
+ body: JSON.stringify({ payload: { data } }),
23
+ });
24
+ }
25
+ export async function deleteSecret(auth, project, secretId) {
26
+ await gcpFetch(auth, secretPath(project, secretId), { method: "DELETE" });
27
+ }
28
+ export async function accessSecretVersion(auth, project, secretId, version = "latest") {
29
+ const url = `${secretPath(project, secretId)}/versions/${version}:access`;
30
+ const data = await gcpFetch(auth, url);
31
+ return Buffer.from(data.payload.data, "base64").toString("utf-8");
32
+ }
33
+ //# sourceMappingURL=secret-manager-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-manager-api.js","sourceRoot":"","sources":["../../../src/cloud/gcp/secret-manager-api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,MAAM,QAAQ,GAAG,yCAAyC,CAAC;AAE3D,SAAS,UAAU,CAAC,OAAe,EAAE,QAAgB;IACnD,OAAO,GAAG,QAAQ,aAAa,OAAO,YAAY,QAAQ,EAAE,CAAC;AAC/D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAa,EACb,OAAe,EACf,QAAgB;IAEhB,MAAM,GAAG,GAAG,GAAG,QAAQ,aAAa,OAAO,qBAAqB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC/F,OAAO,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE;QACzB,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,CAAC;KACzD,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAAa,EACb,OAAe,EACf,QAAgB,EAChB,OAAe;IAEf,MAAM,GAAG,GAAG,GAAG,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,aAAa,CAAC;IAC1D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC9D,OAAO,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE;QACzB,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC;KAC5C,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAa,EACb,OAAe,EACf,QAAgB;IAEhB,MAAM,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAa,EACb,OAAe,EACf,QAAgB,EAChB,OAAO,GAAG,QAAQ;IAElB,MAAM,GAAG,GAAG,GAAG,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,aAAa,OAAO,SAAS,CAAC;IAC1E,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACvC,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACpE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../../src/control/routes/dashboard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEjE;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,IAAI,EACT,aAAa,EAAE,aAAa,GAC3B,IAAI,CA8DN"}
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../../src/control/routes/dashboard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEjE;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,IAAI,EACT,aAAa,EAAE,aAAa,GAC3B,IAAI,CAiFN"}
@@ -44,15 +44,34 @@ export function registerDashboardDataRoutes(app, statusTracker) {
44
44
  };
45
45
  // Send initial state
46
46
  send();
47
+ // Throttle updates: coalesce rapid-fire events into at most 1 send per 500ms
48
+ let pending = false;
49
+ let timer = null;
50
+ const throttledSend = () => {
51
+ if (timer) {
52
+ pending = true;
53
+ return;
54
+ }
55
+ send();
56
+ timer = setTimeout(() => {
57
+ timer = null;
58
+ if (pending) {
59
+ pending = false;
60
+ send();
61
+ }
62
+ }, 500);
63
+ };
47
64
  // Listen for updates
48
- statusTracker.on("update", send);
65
+ statusTracker.on("update", throttledSend);
49
66
  // Keep connection alive with periodic heartbeats
50
67
  const heartbeat = setInterval(() => {
51
68
  stream.writeSSE({ event: "heartbeat", data: "" });
52
69
  }, 15000);
53
70
  // Cleanup on disconnect
54
71
  stream.onAbort(() => {
55
- statusTracker.removeListener("update", send);
72
+ statusTracker.removeListener("update", throttledSend);
73
+ if (timer)
74
+ clearTimeout(timer);
56
75
  clearInterval(heartbeat);
57
76
  });
58
77
  // Keep the stream open
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../src/control/routes/dashboard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../src/control/routes/dashboard.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../../src/control/routes/stats.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEjE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE;QACV,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;QAChC,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,UAAU,EAAE,IAAI,CAAA;SAAE,EAAE,CAAC;KACnE,CAAC;CACH;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,IAAI,EACT,UAAU,CAAC,EAAE,UAAU,EACvB,aAAa,CAAC,EAAE,aAAa,EAC7B,WAAW,CAAC,EAAE,gBAAgB,GAC7B,IAAI,CAqQN"}
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../../src/control/routes/stats.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEjE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE;QACV,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;QAChC,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,UAAU,EAAE,IAAI,CAAA;SAAE,EAAE,CAAC;KACnE,CAAC;CACH;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,IAAI,EACT,UAAU,CAAC,EAAE,UAAU,EACvB,aAAa,CAAC,EAAE,aAAa,EAC7B,WAAW,CAAC,EAAE,gBAAgB,GAC7B,IAAI,CAsQN"}
@@ -216,10 +216,11 @@ export function registerStatsRoutes(app, statsStore, statusTracker, controlDeps)
216
216
  }
217
217
  // Sort all rows by ts descending
218
218
  allRows.sort((a, b) => b.ts - a.ts);
219
- // Apply status filter
219
+ // Apply status filter (supports comma-separated values, e.g. "pending,running,completed")
220
220
  let filtered = allRows;
221
221
  if (statusFilter && statusFilter !== "all") {
222
- filtered = allRows.filter((r) => r.result === statusFilter);
222
+ const statuses = new Set(statusFilter.split(",").map((s) => s.trim()));
223
+ filtered = allRows.filter((r) => statuses.has(r.result));
223
224
  }
224
225
  const total = filtered.length;
225
226
  const paginated = filtered.slice(offset, offset + limit);