@swarmclawai/swarmclaw 1.7.3 → 1.8.1
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 +20 -0
- package/next.config.ts +38 -8
- package/package.json +2 -2
- package/scripts/run-next-build.mjs +51 -3
- package/src/app/api/artifacts/route.ts +15 -0
- package/src/app/api/clawhub/install/route.ts +4 -4
- package/src/app/api/dirs/route.ts +8 -5
- package/src/app/api/files/open/route.ts +3 -3
- package/src/app/api/files/serve/route.ts +2 -2
- package/src/app/api/operations/pulse/route.ts +9 -0
- package/src/app/api/runs/[id]/brief/route.ts +12 -0
- package/src/app/api/runs/[id]/events/route.ts +4 -13
- package/src/app/api/runs/[id]/route.ts +2 -6
- package/src/app/api/runs/route.ts +3 -43
- package/src/app/api/s/[token]/raw/route.ts +1 -1
- package/src/app/home/page.tsx +11 -1
- package/src/app/missions/page.tsx +182 -3
- package/src/app/s/[token]/page.tsx +173 -48
- package/src/cli/index.js +15 -0
- package/src/cli/spec.js +13 -0
- package/src/components/connectors/connector-list.tsx +36 -20
- package/src/components/evidence/evidence-shelf.tsx +97 -0
- package/src/components/home/home-launchpad.tsx +52 -2
- package/src/components/missions/mission-template-install-dialog.tsx +33 -1
- package/src/components/operations/operations-pulse-panel.tsx +184 -0
- package/src/components/quality/quality-workspace.tsx +34 -6
- package/src/components/runs/run-list.tsx +94 -12
- package/src/lib/connectors/connector-readiness.ts +127 -0
- package/src/lib/server/artifacts/artifact-resolver.test.ts +98 -0
- package/src/lib/server/artifacts/artifact-resolver.ts +241 -0
- package/src/lib/server/operations/operation-pulse.test.ts +108 -0
- package/src/lib/server/operations/operation-pulse.ts +197 -0
- package/src/lib/server/resolve-workspace-path.ts +10 -10
- package/src/lib/server/runs/run-brief.test.ts +92 -0
- package/src/lib/server/runs/run-brief.ts +107 -0
- package/src/lib/server/runs/unified-run-queries.ts +84 -0
- package/src/lib/server/sharing/share-resolver.test.ts +129 -0
- package/src/lib/server/sharing/share-resolver.ts +48 -3
- package/src/types/artifact.ts +28 -0
- package/src/types/index.ts +3 -0
- package/src/types/operations.ts +39 -0
- package/src/types/run-brief.ts +41 -0
package/README.md
CHANGED
|
@@ -399,6 +399,26 @@ Operational docs: https://swarmclaw.ai/docs/observability
|
|
|
399
399
|
|
|
400
400
|
## Releases
|
|
401
401
|
|
|
402
|
+
### v1.8.1 Highlights
|
|
403
|
+
|
|
404
|
+
Operator evidence release: a focused follow-up that makes release and mission review easier to scan.
|
|
405
|
+
|
|
406
|
+
- **Operations Pulse.** Home and Quality now share a live triage panel that rolls missions, runs, approvals, connector readiness, and budget pressure into one next-action queue.
|
|
407
|
+
- **Run Briefs.** Run detail sheets now open with a deterministic brief: objective, owner, timeline, warnings, usage, and evidence before the raw replay log.
|
|
408
|
+
- **Evidence Shelf.** Runs and missions now expose linked artifacts, task outputs, protocol outputs, mission reports, public share links, and knowledge citations through a shared artifact resolver.
|
|
409
|
+
- **Connector readiness.** Connector cards now show credential, route, pairing, gateway, connection, and doctor hints so setup gaps are visible before a platform bridge is started.
|
|
410
|
+
- **API surface.** Added `GET /api/operations/pulse`, `GET /api/runs/:id/brief`, and `GET /api/artifacts` for external operator dashboards and release tooling.
|
|
411
|
+
|
|
412
|
+
### v1.8.0 Highlights
|
|
413
|
+
|
|
414
|
+
Mission Command release: a bigger operator update that makes autonomous missions easier to launch, inspect, and share.
|
|
415
|
+
|
|
416
|
+
- **Mission Command launchpad.** The home launchpad now opens concrete mission starters for Release QA, Launch Sprint, Cost Audit, and Connector Smoke Test instead of dropping users into a generic mission list.
|
|
417
|
+
- **Deep-linked mission templates.** `/missions?template=<id>` opens the right starter template directly, and the template installer can create a mission-driver chat when no sessions exist yet.
|
|
418
|
+
- **Quality Center handoffs.** `/quality?tab=evals|approvals|runs` is shareable, and the Quality overview/Eval Lab can start a Release QA mission from current operator evidence.
|
|
419
|
+
- **Public mission reports.** Missions can mint, copy, and revoke public share links from the detail view. Shared pages render status, budgets, milestones, and generated reports using the existing allowlisted share resolver.
|
|
420
|
+
- **Safer share payloads.** Mission milestones now expose `summary` correctly in public HTML and raw markdown shares, with regression coverage in `npm run test:runtime`.
|
|
421
|
+
|
|
402
422
|
### v1.7.3 Highlights
|
|
403
423
|
|
|
404
424
|
Desktop packaging fix for Linux AppImage and deb builds.
|
package/next.config.ts
CHANGED
|
@@ -6,9 +6,39 @@ import path from "path";
|
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
|
|
8
8
|
const PROJECT_ROOT = path.dirname(fileURLToPath(import.meta.url))
|
|
9
|
-
const
|
|
10
|
-
'
|
|
11
|
-
'
|
|
9
|
+
const OUTPUT_TRACE_EXCLUDE_GLOBS = [
|
|
10
|
+
'./.env*',
|
|
11
|
+
'./.git/**/*',
|
|
12
|
+
'./.next/cache/**/*',
|
|
13
|
+
'./.tmp-swarmclaw-build/**/*',
|
|
14
|
+
'./AGENTS.md',
|
|
15
|
+
'./CLAUDE.md',
|
|
16
|
+
'./CONTRIBUTING.md',
|
|
17
|
+
'./Dockerfile',
|
|
18
|
+
'./Dockerfile.*',
|
|
19
|
+
'./README.md',
|
|
20
|
+
'./SWARMDOCK.md',
|
|
21
|
+
'./artifacts/**/*',
|
|
22
|
+
'./components.json',
|
|
23
|
+
'./coverage/**/*',
|
|
24
|
+
'./data/**/*',
|
|
25
|
+
'./daemon.log',
|
|
26
|
+
'./docker-compose.yml',
|
|
27
|
+
'./electron-builder.yml',
|
|
28
|
+
'./electron-dist/**/*',
|
|
29
|
+
'./eslint.config.mjs',
|
|
30
|
+
'./fly.toml',
|
|
31
|
+
'./install.sh',
|
|
32
|
+
'./next.config.ts',
|
|
33
|
+
'./package-lock.json',
|
|
34
|
+
'./postcss.config.mjs',
|
|
35
|
+
'./railway.json',
|
|
36
|
+
'./release/**/*',
|
|
37
|
+
'./render.yaml',
|
|
38
|
+
'./research.md',
|
|
39
|
+
'./swarmclaw-skill.md',
|
|
40
|
+
'./test-results/**/*',
|
|
41
|
+
'./tsconfig.json',
|
|
12
42
|
]
|
|
13
43
|
|
|
14
44
|
function getGitSha(): string {
|
|
@@ -50,11 +80,11 @@ function getAllowedDevOrigins(): string[] {
|
|
|
50
80
|
const nextConfig: NextConfig = {
|
|
51
81
|
output: 'standalone',
|
|
52
82
|
outputFileTracingExcludes: {
|
|
53
|
-
'/*':
|
|
54
|
-
'/api/**':
|
|
55
|
-
instrumentation:
|
|
56
|
-
'/instrumentation':
|
|
57
|
-
'next-server':
|
|
83
|
+
'/*': OUTPUT_TRACE_EXCLUDE_GLOBS,
|
|
84
|
+
'/api/**': OUTPUT_TRACE_EXCLUDE_GLOBS,
|
|
85
|
+
instrumentation: OUTPUT_TRACE_EXCLUDE_GLOBS,
|
|
86
|
+
'/instrumentation': OUTPUT_TRACE_EXCLUDE_GLOBS,
|
|
87
|
+
'next-server': OUTPUT_TRACE_EXCLUDE_GLOBS,
|
|
58
88
|
},
|
|
59
89
|
turbopack: {
|
|
60
90
|
// Pin workspace root to the project directory so a stale lockfile
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swarmclawai/swarmclaw",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "Build and run autonomous AI agents with OpenClaw, Hermes, multiple model providers, orchestration, delegation, memory, skills, schedules, and chat connectors.",
|
|
5
5
|
"main": "electron-dist/main.js",
|
|
6
6
|
"license": "MIT",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"test:cli": "node --test src/cli/*.test.js bin/*.test.js scripts/electron-after-pack.test.mjs scripts/postinstall.test.mjs scripts/run-next-build.test.mjs scripts/run-next-typegen.test.mjs",
|
|
88
88
|
"test:setup": "tsx --test src/app/api/setup/check-provider/route.test.ts src/lib/server/provider-model-discovery.test.ts src/components/auth/setup-wizard/utils.test.ts src/components/auth/setup-wizard/types.test.ts src/hooks/setup-done-detection.test.ts src/lib/setup-defaults.test.ts src/lib/server/storage-auth.test.ts src/lib/server/storage-auth-docker.test.ts",
|
|
89
89
|
"test:openclaw": "tsx --test src/lib/openclaw/openclaw-agent-id.test.ts src/lib/openclaw/openclaw-endpoint.test.ts src/lib/server/agents/agent-runtime-config.test.ts src/lib/server/build-llm.test.ts src/lib/server/connectors/connector-routing.test.ts src/lib/server/connectors/openclaw.test.ts src/lib/server/connectors/swarmdock.test.ts src/lib/server/gateway/protocol.test.ts src/lib/server/llm-response-cache.test.ts src/lib/server/mcp-conformance.test.ts src/lib/server/openclaw/agent-resolver.test.ts src/lib/server/openclaw/deploy.test.ts src/lib/server/openclaw/skills-normalize.test.ts src/lib/server/session-tools/openclaw-nodes.test.ts src/lib/server/session-tools/swarmdock.test.ts src/lib/server/tasks/task-quality-gate.test.ts src/lib/server/tasks/task-validation.test.ts src/lib/server/tool-capability-policy.test.ts src/lib/providers/openai.test.ts src/lib/providers/openclaw-exports.test.ts src/app/api/openclaw/dashboard-url/route.test.ts",
|
|
90
|
-
"test:runtime": "tsx --test src/lib/a2a/agent-card.test.ts src/lib/strip-internal-metadata.test.ts src/lib/provider-sets.test.ts src/lib/providers/opencode-cli.test.ts src/lib/providers/cli-provider-metadata.test.ts src/lib/providers/cli-utils.test.ts src/lib/providers/generic-cli.test.ts src/lib/server/cli-provider-readiness.test.ts src/lib/server/provider-health.test.ts src/lib/server/mcp-gateway-runtime.test.ts src/lib/server/mcp-connection-pool.test.ts src/lib/server/knowledge-sources.test.ts src/lib/server/chat-execution/chat-execution-grounding.test.ts src/lib/server/chat-execution/chat-turn-preparation.test.ts src/lib/server/chat-execution/iteration-timers.test.ts src/lib/server/chat-execution/post-stream-finalization.test.ts src/lib/server/chats/clear-undo-snapshots.test.ts src/lib/server/connectors/email.test.ts src/lib/server/protocols/protocol-service.test.ts src/lib/server/runtime/run-ledger.test.ts src/lib/server/observability/otel-config.test.ts src/lib/server/safe-parse-body.test.ts src/lib/server/missions/mission-templates.test.ts src/lib/app/view-constants.test.ts src/lib/quality/quality-summary.test.ts src/app/api/approvals/route.test.ts src/app/api/agents/agents-route.test.ts src/app/api/tasks/tasks-route.test.ts src/app/api/chats/chat-route.test.ts src/app/api/chats/clear-route.test.ts src/app/api/chats/compact-route.test.ts src/app/api/chats/context-status-route.test.ts src/app/api/connectors/connector-doctor-route.test.ts src/app/api/healthz/route.test.ts src/app/api/logs/route.test.ts src/app/api/providers/[id]/route.test.ts src/app/api/tts/route.test.ts",
|
|
90
|
+
"test:runtime": "tsx --test src/lib/a2a/agent-card.test.ts src/lib/strip-internal-metadata.test.ts src/lib/provider-sets.test.ts src/lib/providers/opencode-cli.test.ts src/lib/providers/cli-provider-metadata.test.ts src/lib/providers/cli-utils.test.ts src/lib/providers/generic-cli.test.ts src/lib/server/cli-provider-readiness.test.ts src/lib/server/provider-health.test.ts src/lib/server/mcp-gateway-runtime.test.ts src/lib/server/mcp-connection-pool.test.ts src/lib/server/knowledge-sources.test.ts src/lib/server/chat-execution/chat-execution-grounding.test.ts src/lib/server/chat-execution/chat-turn-preparation.test.ts src/lib/server/chat-execution/iteration-timers.test.ts src/lib/server/chat-execution/post-stream-finalization.test.ts src/lib/server/chats/clear-undo-snapshots.test.ts src/lib/server/connectors/email.test.ts src/lib/server/protocols/protocol-service.test.ts src/lib/server/runtime/run-ledger.test.ts src/lib/server/runs/run-brief.test.ts src/lib/server/operations/operation-pulse.test.ts src/lib/server/artifacts/artifact-resolver.test.ts src/lib/server/observability/otel-config.test.ts src/lib/server/safe-parse-body.test.ts src/lib/server/missions/mission-templates.test.ts src/lib/server/sharing/share-link-repository.test.ts src/lib/server/sharing/share-resolver.test.ts src/lib/app/view-constants.test.ts src/lib/quality/quality-summary.test.ts src/app/api/approvals/route.test.ts src/app/api/agents/agents-route.test.ts src/app/api/tasks/tasks-route.test.ts src/app/api/chats/chat-route.test.ts src/app/api/chats/clear-route.test.ts src/app/api/chats/compact-route.test.ts src/app/api/chats/context-status-route.test.ts src/app/api/connectors/connector-doctor-route.test.ts src/app/api/healthz/route.test.ts src/app/api/logs/route.test.ts src/app/api/providers/[id]/route.test.ts src/app/api/tts/route.test.ts",
|
|
91
91
|
"test:builder": "tsx --test src/features/protocols/builder/utils/nodes-to-template.test.ts src/features/protocols/builder/utils/template-to-nodes.test.ts src/features/protocols/builder/validators/dag-validator.test.ts",
|
|
92
92
|
"test:e2e": "node --import tsx scripts/browser-e2e-smoke.ts",
|
|
93
93
|
"test:mcp:conformance": "node --import tsx ./scripts/mcp-conformance-check.ts",
|
|
@@ -11,13 +11,15 @@ import { ensureBuildBootstrapPaths } from './build-bootstrap-env.mjs'
|
|
|
11
11
|
|
|
12
12
|
const require = createRequire(import.meta.url)
|
|
13
13
|
|
|
14
|
-
export const DEFAULT_MAX_OLD_SPACE_SIZE_MB = '
|
|
14
|
+
export const DEFAULT_MAX_OLD_SPACE_SIZE_MB = '24576'
|
|
15
15
|
export const MIN_MAX_OLD_SPACE_SIZE_MB = 1024
|
|
16
16
|
export const FALLBACK_MIN_MAX_OLD_SPACE_SIZE_MB = 512
|
|
17
17
|
export const RESERVED_BUILD_MEMORY_MB = 768
|
|
18
|
-
export const MAX_OLD_SPACE_RATIO = 0.
|
|
18
|
+
export const MAX_OLD_SPACE_RATIO = 0.85
|
|
19
19
|
export const LOW_MEMORY_RATIO = 0.6
|
|
20
20
|
export const BUILD_MAX_OLD_SPACE_SIZE_ENV = 'SWARMCLAW_BUILD_MAX_OLD_SPACE_SIZE_MB'
|
|
21
|
+
export const BUILD_BUNDLER_ENV = 'SWARMCLAW_BUILD_BUNDLER'
|
|
22
|
+
export const DEFAULT_BUILD_BUNDLER = 'turbopack'
|
|
21
23
|
export const CGROUP_MEMORY_LIMIT_PATHS = [
|
|
22
24
|
'/sys/fs/cgroup/memory.max',
|
|
23
25
|
'/sys/fs/cgroup/memory/memory.limit_in_bytes',
|
|
@@ -40,6 +42,15 @@ export const REQUIRED_STANDALONE_BROWSER_PACKAGES = [
|
|
|
40
42
|
'playwright',
|
|
41
43
|
'playwright-core',
|
|
42
44
|
]
|
|
45
|
+
export const STANDALONE_LOCAL_STATE_ENTRIES = [
|
|
46
|
+
'.git',
|
|
47
|
+
'.tmp-swarmclaw-build',
|
|
48
|
+
'artifacts',
|
|
49
|
+
'coverage',
|
|
50
|
+
'data',
|
|
51
|
+
'release',
|
|
52
|
+
'test-results',
|
|
53
|
+
]
|
|
43
54
|
|
|
44
55
|
function parsePositiveInteger(value) {
|
|
45
56
|
const parsed = Number.parseInt(String(value ?? '').trim(), 10)
|
|
@@ -133,6 +144,18 @@ export function buildNextBuildEnv(
|
|
|
133
144
|
}
|
|
134
145
|
}
|
|
135
146
|
|
|
147
|
+
export function resolveNextBuildBundlerFlag(args = [], env = process.env) {
|
|
148
|
+
if (args.includes('--webpack') || args.includes('--turbopack')) return null
|
|
149
|
+
|
|
150
|
+
const requested = String(env[BUILD_BUNDLER_ENV] || DEFAULT_BUILD_BUNDLER).trim().toLowerCase()
|
|
151
|
+
if (requested === 'webpack') return '--webpack'
|
|
152
|
+
if (requested === 'turbopack') return '--turbopack'
|
|
153
|
+
|
|
154
|
+
throw new Error(
|
|
155
|
+
`${BUILD_BUNDLER_ENV} must be "turbopack" or "webpack"; received ${JSON.stringify(requested)}.`,
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
136
159
|
export function hasTraceCopyWarning(output = '') {
|
|
137
160
|
return output.includes(TRACE_COPY_WARNING)
|
|
138
161
|
}
|
|
@@ -239,6 +262,27 @@ export function repairStandaloneNextMetadata(cwd = process.cwd()) {
|
|
|
239
262
|
return true
|
|
240
263
|
}
|
|
241
264
|
|
|
265
|
+
export function pruneStandaloneLocalState(cwd = process.cwd()) {
|
|
266
|
+
const standaloneDir = path.join(cwd, '.next', 'standalone')
|
|
267
|
+
if (!fs.existsSync(standaloneDir)) return false
|
|
268
|
+
|
|
269
|
+
let pruned = false
|
|
270
|
+
for (const entry of STANDALONE_LOCAL_STATE_ENTRIES) {
|
|
271
|
+
const target = path.join(standaloneDir, entry)
|
|
272
|
+
if (!fs.existsSync(target)) continue
|
|
273
|
+
fs.rmSync(target, { recursive: true, force: true })
|
|
274
|
+
pruned = true
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
for (const entry of fs.readdirSync(standaloneDir, { withFileTypes: true })) {
|
|
278
|
+
if (entry.name !== '.env' && !entry.name.startsWith('.env.')) continue
|
|
279
|
+
fs.rmSync(path.join(standaloneDir, entry.name), { recursive: entry.isDirectory(), force: true })
|
|
280
|
+
pruned = true
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return pruned
|
|
284
|
+
}
|
|
285
|
+
|
|
242
286
|
export function runNextBuild(
|
|
243
287
|
args = process.argv.slice(2),
|
|
244
288
|
env = process.env,
|
|
@@ -246,7 +290,8 @@ export function runNextBuild(
|
|
|
246
290
|
maxOldSpaceSizeMb = resolveNextBuildMaxOldSpaceSizeMb(env),
|
|
247
291
|
) {
|
|
248
292
|
const nextBin = require.resolve('next/dist/bin/next')
|
|
249
|
-
|
|
293
|
+
const bundlerFlag = resolveNextBuildBundlerFlag(args, env)
|
|
294
|
+
return spawnSync(process.execPath, [nextBin, 'build', ...(bundlerFlag ? [bundlerFlag] : []), ...args], {
|
|
250
295
|
stdio: 'pipe',
|
|
251
296
|
encoding: 'utf-8',
|
|
252
297
|
env: buildNextBuildEnv(env, maxOldSpaceSizeMb, cwd),
|
|
@@ -277,6 +322,9 @@ function main() {
|
|
|
277
322
|
if (result.status === 0 && repairStandaloneBrowserMcpRuntime(process.cwd())) {
|
|
278
323
|
console.error('Copied Playwright MCP runtime packages into standalone build output.')
|
|
279
324
|
}
|
|
325
|
+
if (result.status === 0 && pruneStandaloneLocalState(process.cwd())) {
|
|
326
|
+
console.error('Pruned local state and release artifacts from standalone build output.')
|
|
327
|
+
}
|
|
280
328
|
process.exit(result.status)
|
|
281
329
|
}
|
|
282
330
|
if (result.signal) {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { listEvidenceArtifacts } from '@/lib/server/artifacts/artifact-resolver'
|
|
3
|
+
|
|
4
|
+
export const dynamic = 'force-dynamic'
|
|
5
|
+
|
|
6
|
+
export async function GET(req: Request) {
|
|
7
|
+
const { searchParams } = new URL(req.url)
|
|
8
|
+
const runId = searchParams.get('runId')
|
|
9
|
+
const missionId = searchParams.get('missionId')
|
|
10
|
+
const taskId = searchParams.get('taskId')
|
|
11
|
+
if (!runId && !missionId && !taskId) {
|
|
12
|
+
return NextResponse.json({ error: 'runId, missionId, or taskId is required' }, { status: 400 })
|
|
13
|
+
}
|
|
14
|
+
return NextResponse.json(listEvidenceArtifacts({ runId, missionId, taskId }))
|
|
15
|
+
}
|
|
@@ -48,7 +48,7 @@ async function writeClawHubBundleToWorkspace(bundle: ClawHubSkillBundle): Promis
|
|
|
48
48
|
.filter((entry): entry is { file: ClawHubSkillBundle['files'][number], path: string } => Boolean(entry.path))
|
|
49
49
|
|
|
50
50
|
const workspaceSkillsDir = resolveWorkspaceSkillsDir()
|
|
51
|
-
const targetDir = path.join(workspaceSkillsDir, sanitizeSkillDirName(bundle.slug))
|
|
51
|
+
const targetDir = path.join(/*turbopackIgnore: true*/ workspaceSkillsDir, sanitizeSkillDirName(bundle.slug))
|
|
52
52
|
const normalizedPaths = stripSharedTopLevelDir(normalizedEntries.map((entry) => entry.path))
|
|
53
53
|
|
|
54
54
|
await fs.rm(targetDir, { recursive: true, force: true })
|
|
@@ -57,12 +57,12 @@ async function writeClawHubBundleToWorkspace(bundle: ClawHubSkillBundle): Promis
|
|
|
57
57
|
for (let index = 0; index < normalizedEntries.length; index += 1) {
|
|
58
58
|
const relativePath = normalizedPaths[index]
|
|
59
59
|
if (!relativePath) continue
|
|
60
|
-
const destination = path.join(targetDir, relativePath)
|
|
60
|
+
const destination = path.join(/*turbopackIgnore: true*/ targetDir, relativePath)
|
|
61
61
|
if (!destination.startsWith(targetDir + path.sep) && destination !== targetDir) {
|
|
62
62
|
throw new Error(`Refusing to write bundle file outside the target directory: ${relativePath}`)
|
|
63
63
|
}
|
|
64
|
-
await fs.mkdir(path.dirname(destination), { recursive: true })
|
|
65
|
-
await fs.writeFile(destination, normalizedEntries[index].file.content)
|
|
64
|
+
await fs.mkdir(/*turbopackIgnore: true*/ path.dirname(destination), { recursive: true })
|
|
65
|
+
await fs.writeFile(/*turbopackIgnore: true*/ destination, normalizedEntries[index].file.content)
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
clearDiscoveredSkillsCache()
|
|
@@ -9,18 +9,21 @@ export async function GET(req: NextRequest) {
|
|
|
9
9
|
|
|
10
10
|
// Resolve ~ to home dir
|
|
11
11
|
const resolved = targetDir.startsWith('~')
|
|
12
|
-
? path.join(os.homedir(), targetDir.slice(1))
|
|
13
|
-
: path.resolve(targetDir)
|
|
12
|
+
? path.join(/*turbopackIgnore: true*/ os.homedir(), targetDir.slice(1))
|
|
13
|
+
: path.resolve(/*turbopackIgnore: true*/ targetDir)
|
|
14
14
|
|
|
15
15
|
let dirs: Array<{ name: string; path: string }> = []
|
|
16
16
|
try {
|
|
17
|
-
dirs = fs.readdirSync(resolved)
|
|
17
|
+
dirs = fs.readdirSync(/*turbopackIgnore: true*/ resolved)
|
|
18
18
|
.filter(d => {
|
|
19
19
|
if (d.startsWith('.')) return false
|
|
20
|
-
try {
|
|
20
|
+
try {
|
|
21
|
+
const childPath = path.join(/*turbopackIgnore: true*/ resolved, d)
|
|
22
|
+
return fs.statSync(/*turbopackIgnore: true*/ childPath).isDirectory()
|
|
23
|
+
} catch { return false }
|
|
21
24
|
})
|
|
22
25
|
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
|
|
23
|
-
.map(d => ({ name: d, path: path.join(resolved, d) }))
|
|
26
|
+
.map(d => ({ name: d, path: path.join(/*turbopackIgnore: true*/ resolved, d) }))
|
|
24
27
|
} catch {}
|
|
25
28
|
|
|
26
29
|
const parentPath = resolved === '/' ? null : path.dirname(resolved)
|
|
@@ -19,7 +19,7 @@ export async function POST(req: Request) {
|
|
|
19
19
|
return NextResponse.json({ error: 'Path does not exist' }, { status: 404 })
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
const isDir = fs.statSync(resolved).isDirectory()
|
|
22
|
+
const isDir = fs.statSync(/*turbopackIgnore: true*/ resolved).isDirectory()
|
|
23
23
|
const platform = process.platform
|
|
24
24
|
|
|
25
25
|
let command: string
|
|
@@ -32,11 +32,11 @@ export async function POST(req: Request) {
|
|
|
32
32
|
args = isDir ? [resolved] : [`/select,${resolved}`]
|
|
33
33
|
} else {
|
|
34
34
|
command = 'xdg-open'
|
|
35
|
-
args = [isDir ? resolved : path.dirname(resolved)]
|
|
35
|
+
args = [isDir ? resolved : path.dirname(/*turbopackIgnore: true*/ resolved)]
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
return new Promise<NextResponse>((resolve) => {
|
|
39
|
-
const child = spawn(command, args, { stdio: 'ignore' })
|
|
39
|
+
const child = spawn(/*turbopackIgnore: true*/ command, args, { stdio: 'ignore' })
|
|
40
40
|
child.once('error', (err) => {
|
|
41
41
|
resolve(NextResponse.json({ error: err.message }, { status: 500 }))
|
|
42
42
|
})
|
|
@@ -57,7 +57,7 @@ export async function GET(req: Request) {
|
|
|
57
57
|
return NextResponse.json({ error: 'Access denied' }, { status: 403 })
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
const stat = fs.statSync(resolved)
|
|
60
|
+
const stat = fs.statSync(/*turbopackIgnore: true*/ resolved)
|
|
61
61
|
if (!stat.isFile()) {
|
|
62
62
|
return NextResponse.json({ error: 'Not a file' }, { status: 400 })
|
|
63
63
|
}
|
|
@@ -67,7 +67,7 @@ export async function GET(req: Request) {
|
|
|
67
67
|
|
|
68
68
|
const ext = path.extname(resolved).toLowerCase()
|
|
69
69
|
const contentType = MIME_MAP[ext] || 'application/octet-stream'
|
|
70
|
-
const content = fs.readFileSync(resolved)
|
|
70
|
+
const content = fs.readFileSync(/*turbopackIgnore: true*/ resolved)
|
|
71
71
|
|
|
72
72
|
return new NextResponse(content, {
|
|
73
73
|
headers: {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { getOperationPulse, normalizeOperationPulseRange } from '@/lib/server/operations/operation-pulse'
|
|
3
|
+
|
|
4
|
+
export const dynamic = 'force-dynamic'
|
|
5
|
+
|
|
6
|
+
export async function GET(req: Request) {
|
|
7
|
+
const { searchParams } = new URL(req.url)
|
|
8
|
+
return NextResponse.json(getOperationPulse(normalizeOperationPulseRange(searchParams.get('range'))))
|
|
9
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server'
|
|
2
|
+
import { buildRunBrief } from '@/lib/server/runs/run-brief'
|
|
3
|
+
import { getUnifiedRunById, listUnifiedRunEvents } from '@/lib/server/runs/unified-run-queries'
|
|
4
|
+
|
|
5
|
+
export const dynamic = 'force-dynamic'
|
|
6
|
+
|
|
7
|
+
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
8
|
+
const { id } = await params
|
|
9
|
+
const run = getUnifiedRunById(id)
|
|
10
|
+
if (!run) return NextResponse.json({ error: 'Run not found' }, { status: 404 })
|
|
11
|
+
return NextResponse.json(buildRunBrief(run, listUnifiedRunEvents(id, 300)))
|
|
12
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
-
import {
|
|
3
|
-
import { listProtocolRunEventsForRun, loadProtocolRunById } from '@/lib/server/protocols/protocol-queries'
|
|
4
|
-
import { protocolEventToRunEventRecord } from '@/lib/server/runs/unified-run-records'
|
|
2
|
+
import { getUnifiedRunById, listUnifiedRunEvents } from '@/lib/server/runs/unified-run-queries'
|
|
5
3
|
|
|
6
4
|
export const dynamic = 'force-dynamic'
|
|
7
5
|
|
|
@@ -13,16 +11,9 @@ function parseLimit(value: string | null): number | undefined {
|
|
|
13
11
|
|
|
14
12
|
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
15
13
|
const { id } = await params
|
|
16
|
-
const run =
|
|
17
|
-
if (run) {
|
|
18
|
-
const url = new URL(req.url)
|
|
19
|
-
const limit = parseLimit(url.searchParams.get('limit'))
|
|
20
|
-
return NextResponse.json(listRunEvents(id, limit))
|
|
21
|
-
}
|
|
22
|
-
const protocolRun = loadProtocolRunById(id)
|
|
23
|
-
if (!protocolRun) return NextResponse.json({ error: 'Run not found' }, { status: 404 })
|
|
14
|
+
const run = getUnifiedRunById(id)
|
|
15
|
+
if (!run) return NextResponse.json({ error: 'Run not found' }, { status: 404 })
|
|
24
16
|
const url = new URL(req.url)
|
|
25
17
|
const limit = parseLimit(url.searchParams.get('limit'))
|
|
26
|
-
|
|
27
|
-
return NextResponse.json(events)
|
|
18
|
+
return NextResponse.json(listUnifiedRunEvents(id, limit || 200))
|
|
28
19
|
}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
-
import {
|
|
3
|
-
import { loadProtocolRunById } from '@/lib/server/protocols/protocol-queries'
|
|
4
|
-
import { protocolRunToSessionRunRecord } from '@/lib/server/runs/unified-run-records'
|
|
2
|
+
import { getUnifiedRunById } from '@/lib/server/runs/unified-run-queries'
|
|
5
3
|
|
|
6
4
|
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
7
5
|
const { id } = await params
|
|
8
|
-
const run =
|
|
6
|
+
const run = getUnifiedRunById(id)
|
|
9
7
|
if (run) return NextResponse.json(run)
|
|
10
|
-
const protocolRun = loadProtocolRunById(id)
|
|
11
|
-
if (protocolRun) return NextResponse.json(protocolRunToSessionRunRecord(protocolRun))
|
|
12
8
|
return NextResponse.json({ error: 'Run not found' }, { status: 404 })
|
|
13
9
|
}
|
|
@@ -1,28 +1,9 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { protocolRunToSessionRunRecord } from '@/lib/server/runs/unified-run-records'
|
|
5
|
-
import type { ProtocolRunStatus, SessionRunStatus } from '@/types'
|
|
2
|
+
import { listUnifiedRuns } from '@/lib/server/runs/unified-run-queries'
|
|
3
|
+
import type { SessionRunStatus } from '@/types'
|
|
6
4
|
|
|
7
5
|
export const dynamic = 'force-dynamic'
|
|
8
6
|
|
|
9
|
-
function protocolStatusesForRunStatus(status?: SessionRunStatus): ProtocolRunStatus[] {
|
|
10
|
-
switch (status) {
|
|
11
|
-
case 'queued':
|
|
12
|
-
return ['draft']
|
|
13
|
-
case 'running':
|
|
14
|
-
return ['running', 'waiting', 'paused']
|
|
15
|
-
case 'completed':
|
|
16
|
-
return ['completed']
|
|
17
|
-
case 'failed':
|
|
18
|
-
return ['failed']
|
|
19
|
-
case 'cancelled':
|
|
20
|
-
return ['cancelled', 'archived']
|
|
21
|
-
default:
|
|
22
|
-
return []
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
7
|
export async function GET(req: Request) {
|
|
27
8
|
const { searchParams } = new URL(req.url)
|
|
28
9
|
const sessionId = searchParams.get('sessionId') || undefined
|
|
@@ -30,26 +11,5 @@ export async function GET(req: Request) {
|
|
|
30
11
|
const limitRaw = searchParams.get('limit')
|
|
31
12
|
const limit = limitRaw ? Number.parseInt(limitRaw, 10) : undefined
|
|
32
13
|
|
|
33
|
-
|
|
34
|
-
const fetchLimit = limit || 200
|
|
35
|
-
const scopedProtocolRuns = status
|
|
36
|
-
? protocolStatusesForRunStatus(status).flatMap((protocolStatus) => listProtocolRuns({
|
|
37
|
-
includeSystemOwned: true,
|
|
38
|
-
sessionId,
|
|
39
|
-
status: protocolStatus,
|
|
40
|
-
limit: fetchLimit,
|
|
41
|
-
}))
|
|
42
|
-
: listProtocolRuns({
|
|
43
|
-
includeSystemOwned: true,
|
|
44
|
-
sessionId,
|
|
45
|
-
limit: fetchLimit,
|
|
46
|
-
})
|
|
47
|
-
const protocolRuns = Array.from(new Map(scopedProtocolRuns.map((run) => [run.id, run])).values())
|
|
48
|
-
.filter((run) => run.status !== 'archived')
|
|
49
|
-
.map(protocolRunToSessionRunRecord)
|
|
50
|
-
.filter((run) => !status || run.status === status)
|
|
51
|
-
const runs = [...sessionRuns, ...protocolRuns]
|
|
52
|
-
.sort((left, right) => (right.queuedAt || 0) - (left.queuedAt || 0))
|
|
53
|
-
.slice(0, fetchLimit)
|
|
54
|
-
return NextResponse.json(runs)
|
|
14
|
+
return NextResponse.json(listUnifiedRuns({ sessionId, status, limit }))
|
|
55
15
|
}
|
|
@@ -49,7 +49,7 @@ export async function GET(_req: Request, ctx: { params: Promise<{ token: string
|
|
|
49
49
|
if (payload.milestones.length > 0) {
|
|
50
50
|
lines.push('## Milestones', '')
|
|
51
51
|
for (const m of payload.milestones) {
|
|
52
|
-
lines.push(`- ${new Date(m.at).toISOString().slice(0, 19).replace('T', ' ')}: ${m.
|
|
52
|
+
lines.push(`- ${new Date(m.at).toISOString().slice(0, 19).replace('T', ' ')}: ${m.summary}`)
|
|
53
53
|
}
|
|
54
54
|
lines.push('')
|
|
55
55
|
}
|
package/src/app/home/page.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import { useAppStore } from '@/stores/use-app-store'
|
|
|
7
7
|
import { useChatStore } from '@/stores/use-chat-store'
|
|
8
8
|
import { AgentAvatar } from '@/components/agents/agent-avatar'
|
|
9
9
|
import { HomeLaunchpad } from '@/components/home/home-launchpad'
|
|
10
|
+
import { OperationsPulsePanel } from '@/components/operations/operations-pulse-panel'
|
|
10
11
|
import { useMountedRef } from '@/hooks/use-mounted-ref'
|
|
11
12
|
import { useNow } from '@/hooks/use-now'
|
|
12
13
|
import { api } from '@/lib/app/api-client'
|
|
@@ -266,6 +267,10 @@ export default function HomePage() {
|
|
|
266
267
|
router.push(DEFAULT_BUILDER_ROUTE)
|
|
267
268
|
}
|
|
268
269
|
|
|
270
|
+
const openMissionTemplate = (templateId: string) => {
|
|
271
|
+
router.push(`/missions?template=${encodeURIComponent(templateId)}`)
|
|
272
|
+
}
|
|
273
|
+
|
|
269
274
|
if (homeMode === 'launchpad') {
|
|
270
275
|
return (
|
|
271
276
|
<MainContent>
|
|
@@ -286,7 +291,10 @@ export default function HomePage() {
|
|
|
286
291
|
onRunEvalSuite={() => navigateTo('quality')}
|
|
287
292
|
onReviewApprovals={() => navigateTo('quality')}
|
|
288
293
|
onInspectFailedRuns={() => navigateTo('quality')}
|
|
289
|
-
onStartReleaseQaMission={() =>
|
|
294
|
+
onStartReleaseQaMission={() => openMissionTemplate('release-candidate-qa')}
|
|
295
|
+
onStartLaunchSprintMission={() => openMissionTemplate('launch-week-growth-sprint')}
|
|
296
|
+
onStartCostAuditMission={() => openMissionTemplate('agent-cost-audit')}
|
|
297
|
+
onStartConnectorSmokeMission={() => openMissionTemplate('connector-smoke-test')}
|
|
290
298
|
/>
|
|
291
299
|
</div>
|
|
292
300
|
</MainContent>
|
|
@@ -307,6 +315,8 @@ export default function HomePage() {
|
|
|
307
315
|
</p>
|
|
308
316
|
</div>
|
|
309
317
|
|
|
318
|
+
<OperationsPulsePanel className="mb-8" compact />
|
|
319
|
+
|
|
310
320
|
{/* Quick actions / triage */}
|
|
311
321
|
<section className="mb-8" style={{ animation: 'fade-up 0.6s var(--ease-spring) 0.15s both' }}>
|
|
312
322
|
<SectionHeader
|