@treeseed/core 0.4.9 → 0.4.11
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 -2
- package/dist/agent.d.ts +0 -1
- package/dist/agent.js +0 -2
- package/dist/agents/spec-types.d.ts +10 -10
- package/dist/api/agent-routes.d.ts +2 -2
- package/dist/api/agent-routes.js +51 -125
- package/dist/api/app.js +56 -4
- package/dist/api/auth/d1-store.d.ts +1 -0
- package/dist/api/auth/d1-store.js +21 -1
- package/dist/api/auth/rbac.d.ts +2 -2
- package/dist/api/auth/rbac.js +2 -1
- package/dist/api/config.js +4 -0
- package/dist/api/http.d.ts +4 -0
- package/dist/api/http.js +7 -0
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.js +2 -2
- package/dist/api/operations-routes.d.ts +1 -0
- package/dist/api/operations-routes.js +6 -1
- package/dist/api/railway.d.ts +4 -0
- package/dist/api/sdk-dispatch.d.ts +2 -11
- package/dist/api/sdk-dispatch.js +1 -133
- package/dist/api/sdk-routes.d.ts +1 -0
- package/dist/api/sdk-routes.js +5 -1
- package/dist/api/types.d.ts +32 -16
- package/dist/components/site/RouteNotFound.astro +25 -0
- package/dist/content-config.d.ts +1 -0
- package/dist/content.d.ts +1 -0
- package/dist/content.js +177 -1
- package/dist/dev.d.ts +7 -2
- package/dist/dev.js +83 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +9 -3
- package/dist/middleware/editorial-preview.d.ts +26 -0
- package/dist/middleware/editorial-preview.js +37 -0
- package/dist/middleware/starlightRouteData.js +15 -4
- package/dist/pages/[slug].astro +12 -10
- package/dist/pages/agents/[slug].astro +28 -21
- package/dist/pages/books/[slug].astro +19 -12
- package/dist/pages/feed.xml.js +6 -4
- package/dist/pages/index.astro +43 -14
- package/dist/pages/notes/[slug].astro +19 -12
- package/dist/pages/objectives/[slug].astro +30 -23
- package/dist/pages/people/[slug].astro +28 -21
- package/dist/pages/questions/[slug].astro +30 -23
- package/dist/scripts/build-dist.js +6 -1
- package/dist/scripts/dev-platform.js +9 -1
- package/dist/scripts/test-smoke.js +0 -1
- package/dist/services/agents.d.ts +22 -0
- package/dist/services/agents.js +29 -0
- package/dist/services/common.d.ts +37 -4
- package/dist/services/common.js +135 -17
- package/dist/services/index.d.ts +4 -1
- package/dist/services/index.js +14 -2
- package/dist/services/manager.d.ts +246 -3
- package/dist/services/manager.js +1101 -171
- package/dist/services/remote-runner.d.ts +30 -0
- package/dist/services/remote-runner.js +111 -0
- package/dist/services/workday-content.d.ts +53 -0
- package/dist/services/workday-content.js +190 -0
- package/dist/services/workday-report.d.ts +160 -2
- package/dist/services/workday-report.js +4 -31
- package/dist/services/workday-start.d.ts +174 -1
- package/dist/services/workday-start.js +3 -13
- package/dist/services/worker-pool-scaler.d.ts +27 -0
- package/dist/services/worker-pool-scaler.js +109 -0
- package/dist/services/worker.d.ts +7 -0
- package/dist/services/worker.js +41 -57
- package/dist/site.js +43 -27
- package/dist/templates.d.ts +98 -0
- package/dist/templates.js +170 -0
- package/dist/tenant/runtime-config.d.ts +4 -0
- package/dist/tenant/runtime-config.js +34 -1
- package/dist/utils/hub-content.js +35 -0
- package/dist/utils/published-content.js +60 -0
- package/dist/utils/site-models.d.ts +6 -0
- package/dist/utils/site-models.js +16 -0
- package/dist/utils/starlight-nav.js +50 -0
- package/package.json +23 -9
- package/templates/github/deploy.workflow.yml +404 -9
- package/templates/github/hosted-project.workflow.yml +77 -0
- package/dist/api/gateway.d.ts +0 -5
- package/dist/api/gateway.js +0 -35
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { AgentSdk } from '@treeseed/sdk';
|
|
3
|
+
export declare function resolveRemoteRunnerConfig(): {
|
|
4
|
+
marketBaseUrl: string;
|
|
5
|
+
projectId: string;
|
|
6
|
+
runnerToken: string;
|
|
7
|
+
runnerId: string;
|
|
8
|
+
batchSize: number;
|
|
9
|
+
pollIntervalMs: number;
|
|
10
|
+
};
|
|
11
|
+
export declare function runRemoteRunnerCycle(options?: {
|
|
12
|
+
sdk?: AgentSdk;
|
|
13
|
+
config?: ReturnType<typeof resolveRemoteRunnerConfig>;
|
|
14
|
+
fetchImpl?: typeof fetch;
|
|
15
|
+
}): Promise<{
|
|
16
|
+
ok: boolean;
|
|
17
|
+
processed: number;
|
|
18
|
+
idle: boolean;
|
|
19
|
+
reason: string;
|
|
20
|
+
} | {
|
|
21
|
+
ok: boolean;
|
|
22
|
+
processed: number;
|
|
23
|
+
idle?: undefined;
|
|
24
|
+
reason?: undefined;
|
|
25
|
+
}>;
|
|
26
|
+
export declare function startRemoteRunnerLoop(options?: {
|
|
27
|
+
sdk?: AgentSdk;
|
|
28
|
+
config?: ReturnType<typeof resolveRemoteRunnerConfig>;
|
|
29
|
+
fetchImpl?: typeof fetch;
|
|
30
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { AgentSdk, RemoteTreeseedClient, RemoteTreeseedRunnerClient } from "@treeseed/sdk";
|
|
4
|
+
import { createServiceSdk } from "./common.js";
|
|
5
|
+
function integerFromEnv(name, fallback) {
|
|
6
|
+
const value = process.env[name];
|
|
7
|
+
if (!value) return fallback;
|
|
8
|
+
const parsed = Number.parseInt(value, 10);
|
|
9
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
10
|
+
}
|
|
11
|
+
function envValue(name) {
|
|
12
|
+
const value = process.env[name]?.trim();
|
|
13
|
+
return value ? value : "";
|
|
14
|
+
}
|
|
15
|
+
function resolveRemoteRunnerConfig() {
|
|
16
|
+
return {
|
|
17
|
+
marketBaseUrl: envValue("TREESEED_MARKET_API_BASE_URL") || envValue("TREESEED_API_BASE_URL"),
|
|
18
|
+
projectId: envValue("TREESEED_PROJECT_ID") || "treeseed-market",
|
|
19
|
+
runnerToken: envValue("TREESEED_PROJECT_RUNNER_TOKEN"),
|
|
20
|
+
runnerId: envValue("TREESEED_REMOTE_RUNNER_ID") || `remote-runner-${process.pid}`,
|
|
21
|
+
batchSize: integerFromEnv("TREESEED_REMOTE_RUNNER_BATCH_SIZE", 1),
|
|
22
|
+
pollIntervalMs: integerFromEnv("TREESEED_REMOTE_RUNNER_POLL_INTERVAL_MS", 5e3)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function createRunnerClient(config, fetchImpl) {
|
|
26
|
+
if (!config.marketBaseUrl || !config.runnerToken) {
|
|
27
|
+
if (process.env.TREESEED_LOCAL_DEV_MODE?.trim()) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
throw new Error(
|
|
31
|
+
"Remote runner requires TREESEED_MARKET_API_BASE_URL (or TREESEED_API_BASE_URL) and TREESEED_PROJECT_RUNNER_TOKEN."
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
return new RemoteTreeseedRunnerClient(new RemoteTreeseedClient({
|
|
35
|
+
hosts: [{ id: "market", baseUrl: config.marketBaseUrl }],
|
|
36
|
+
activeHostId: "market",
|
|
37
|
+
auth: {
|
|
38
|
+
accessToken: config.runnerToken
|
|
39
|
+
}
|
|
40
|
+
}, {
|
|
41
|
+
fetchImpl
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
async function runRemoteRunnerCycle(options = {}) {
|
|
45
|
+
const config = options.config ?? resolveRemoteRunnerConfig();
|
|
46
|
+
const sdk = options.sdk ?? createServiceSdk();
|
|
47
|
+
const runner = createRunnerClient(config, options.fetchImpl);
|
|
48
|
+
if (!runner) {
|
|
49
|
+
return { ok: true, processed: 0, idle: true, reason: "registration_unconfigured" };
|
|
50
|
+
}
|
|
51
|
+
const pulled = await runner.pull(config.projectId, {
|
|
52
|
+
limit: config.batchSize,
|
|
53
|
+
runnerId: config.runnerId
|
|
54
|
+
});
|
|
55
|
+
if (pulled.payload.length === 0) {
|
|
56
|
+
return { ok: true, processed: 0 };
|
|
57
|
+
}
|
|
58
|
+
let processed = 0;
|
|
59
|
+
for (const job of pulled.payload) {
|
|
60
|
+
try {
|
|
61
|
+
await runner.progress(job.id, {
|
|
62
|
+
summary: `Running ${job.namespace}:${job.operation}`,
|
|
63
|
+
data: {
|
|
64
|
+
runnerId: config.runnerId,
|
|
65
|
+
status: "running"
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
const result = await sdk.dispatch({
|
|
69
|
+
namespace: job.namespace,
|
|
70
|
+
operation: job.operation,
|
|
71
|
+
input: job.input ?? {},
|
|
72
|
+
preferredMode: "prefer_local"
|
|
73
|
+
});
|
|
74
|
+
await runner.complete(job.id, {
|
|
75
|
+
output: result.mode === "inline" ? result.payload : result
|
|
76
|
+
});
|
|
77
|
+
processed += 1;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
await runner.fail(job.id, {
|
|
80
|
+
code: "runner_execution_failed",
|
|
81
|
+
message: error instanceof Error ? error.message : String(error)
|
|
82
|
+
}).catch(() => null);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return { ok: true, processed };
|
|
86
|
+
}
|
|
87
|
+
async function startRemoteRunnerLoop(options = {}) {
|
|
88
|
+
const config = options.config ?? resolveRemoteRunnerConfig();
|
|
89
|
+
for (; ; ) {
|
|
90
|
+
try {
|
|
91
|
+
await runRemoteRunnerCycle({
|
|
92
|
+
...options,
|
|
93
|
+
config
|
|
94
|
+
});
|
|
95
|
+
} catch (error) {
|
|
96
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}
|
|
97
|
+
`);
|
|
98
|
+
}
|
|
99
|
+
await new Promise((resolvePromise) => setTimeout(resolvePromise, config.pollIntervalMs));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
103
|
+
const entryFile = process.argv[1] ?? "";
|
|
104
|
+
if (entryFile === currentFile) {
|
|
105
|
+
await startRemoteRunnerLoop();
|
|
106
|
+
}
|
|
107
|
+
export {
|
|
108
|
+
resolveRemoteRunnerConfig,
|
|
109
|
+
runRemoteRunnerCycle,
|
|
110
|
+
startRemoteRunnerLoop
|
|
111
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { PrioritySnapshot, ScaleDecision, WorkerPoolScaleResult } from '@treeseed/sdk';
|
|
2
|
+
type JsonRecord = Record<string, unknown>;
|
|
3
|
+
export interface WorkdayContentTaskSummary {
|
|
4
|
+
id: string;
|
|
5
|
+
agentId?: string;
|
|
6
|
+
type?: string;
|
|
7
|
+
state?: string;
|
|
8
|
+
priority?: number;
|
|
9
|
+
idempotencyKey?: string;
|
|
10
|
+
createdAt?: string | null;
|
|
11
|
+
startedAt?: string | null;
|
|
12
|
+
completedAt?: string | null;
|
|
13
|
+
lastErrorCode?: string | null;
|
|
14
|
+
lastErrorMessage?: string | null;
|
|
15
|
+
lastEventKind?: string | null;
|
|
16
|
+
outputCount?: number;
|
|
17
|
+
changedFiles?: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface WorkdayContentReleaseRecord {
|
|
20
|
+
id?: string;
|
|
21
|
+
deploymentKind: string;
|
|
22
|
+
status: string;
|
|
23
|
+
releaseTag?: string | null;
|
|
24
|
+
commitSha?: string | null;
|
|
25
|
+
sourceRef?: string | null;
|
|
26
|
+
startedAt?: string | null;
|
|
27
|
+
finishedAt?: string | null;
|
|
28
|
+
createdAt?: string | null;
|
|
29
|
+
}
|
|
30
|
+
export interface WorkdayContentSnapshotInput {
|
|
31
|
+
repoRoot: string;
|
|
32
|
+
projectId: string;
|
|
33
|
+
teamId: string;
|
|
34
|
+
environment: string;
|
|
35
|
+
workDay: JsonRecord;
|
|
36
|
+
summary: JsonRecord;
|
|
37
|
+
prioritySnapshot: PrioritySnapshot | null;
|
|
38
|
+
scaleDecision: ScaleDecision;
|
|
39
|
+
scaleResult: WorkerPoolScaleResult;
|
|
40
|
+
tasks: WorkdayContentTaskSummary[];
|
|
41
|
+
changedFiles: string[];
|
|
42
|
+
releases: WorkdayContentReleaseRecord[];
|
|
43
|
+
generatedAt: string;
|
|
44
|
+
}
|
|
45
|
+
export interface WorkdayContentSnapshotResult {
|
|
46
|
+
filePath: string;
|
|
47
|
+
relativePath: string;
|
|
48
|
+
slug: string;
|
|
49
|
+
reportVersion: string;
|
|
50
|
+
title: string;
|
|
51
|
+
}
|
|
52
|
+
export declare function writeWorkdayContentSnapshot(input: WorkdayContentSnapshotInput): WorkdayContentSnapshotResult;
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { relative, resolve } from "node:path";
|
|
4
|
+
import { stringify as stringifyYaml } from "yaml";
|
|
5
|
+
function stableHash(value) {
|
|
6
|
+
return createHash("sha256").update(value).digest("hex");
|
|
7
|
+
}
|
|
8
|
+
function sanitizeSegment(value, fallback) {
|
|
9
|
+
const normalized = value.trim().replaceAll(/[\\/]+/g, "-").replaceAll(/[^a-zA-Z0-9._-]+/g, "-").replaceAll(/-+/g, "-").replaceAll(/^-|-$/g, "");
|
|
10
|
+
return normalized || fallback;
|
|
11
|
+
}
|
|
12
|
+
function compactTimestamp(value) {
|
|
13
|
+
return value.replaceAll(/[-:]/g, "").replace(/\.\d{3}Z$/u, "Z");
|
|
14
|
+
}
|
|
15
|
+
function toIsoDate(value) {
|
|
16
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const parsed = new Date(value);
|
|
20
|
+
return Number.isFinite(parsed.valueOf()) ? parsed.toISOString() : null;
|
|
21
|
+
}
|
|
22
|
+
function bodySummary(summary) {
|
|
23
|
+
return typeof summary.summary === "string" && summary.summary.trim() ? summary.summary.trim() : `Completed ${Number(summary.completedTasks ?? 0)} tasks, with ${Number(summary.failedTasks ?? 0)} failures and ${Number(summary.remainingTaskCredits ?? 0)} remaining task credits.`;
|
|
24
|
+
}
|
|
25
|
+
function renderTasks(tasks) {
|
|
26
|
+
if (tasks.length === 0) {
|
|
27
|
+
return "- No tasks were recorded.\n";
|
|
28
|
+
}
|
|
29
|
+
return tasks.map((task) => {
|
|
30
|
+
const suffix = [
|
|
31
|
+
task.state ? `state: ${task.state}` : null,
|
|
32
|
+
task.agentId ? `agent: ${task.agentId}` : null,
|
|
33
|
+
Number.isFinite(task.priority) ? `priority: ${task.priority}` : null,
|
|
34
|
+
task.lastEventKind ? `last event: ${task.lastEventKind}` : null,
|
|
35
|
+
task.outputCount ? `outputs: ${task.outputCount}` : null
|
|
36
|
+
].filter(Boolean).join(", ");
|
|
37
|
+
return `- \`${task.id}\` ${task.type ?? "task"}${suffix ? ` (${suffix})` : ""}`;
|
|
38
|
+
}).join("\n") + "\n";
|
|
39
|
+
}
|
|
40
|
+
function renderChangedFiles(changedFiles) {
|
|
41
|
+
if (changedFiles.length === 0) {
|
|
42
|
+
return "- No changed files were reported by task outputs.\n";
|
|
43
|
+
}
|
|
44
|
+
return changedFiles.map((filePath) => `- \`${filePath}\``).join("\n") + "\n";
|
|
45
|
+
}
|
|
46
|
+
function renderReleases(releases) {
|
|
47
|
+
if (releases.length === 0) {
|
|
48
|
+
return "- No releases or deployments were recorded during this workday.\n";
|
|
49
|
+
}
|
|
50
|
+
return releases.map((release) => {
|
|
51
|
+
const label = release.releaseTag || release.commitSha || release.id || release.deploymentKind;
|
|
52
|
+
const details = [release.deploymentKind, release.status, release.sourceRef].filter(Boolean).join(", ");
|
|
53
|
+
return `- \`${label}\`${details ? ` (${details})` : ""}`;
|
|
54
|
+
}).join("\n") + "\n";
|
|
55
|
+
}
|
|
56
|
+
function renderPriorityItems(snapshot) {
|
|
57
|
+
if (!snapshot?.items?.length) {
|
|
58
|
+
return "- No priority snapshot items were captured.\n";
|
|
59
|
+
}
|
|
60
|
+
return snapshot.items.map((item) => {
|
|
61
|
+
const details = [
|
|
62
|
+
item.model,
|
|
63
|
+
Number.isFinite(item.priority) ? `priority: ${item.priority}` : null,
|
|
64
|
+
Number.isFinite(item.estimatedCredits) ? `credits: ${item.estimatedCredits}` : null
|
|
65
|
+
].filter(Boolean).join(", ");
|
|
66
|
+
return `- \`${item.id}\`${item.title ? ` ${item.title}` : ""}${details ? ` (${details})` : ""}`;
|
|
67
|
+
}).join("\n") + "\n";
|
|
68
|
+
}
|
|
69
|
+
function buildMarkdownBody(input) {
|
|
70
|
+
const summaryText = bodySummary(input.summary);
|
|
71
|
+
return [
|
|
72
|
+
summaryText,
|
|
73
|
+
"",
|
|
74
|
+
"## Budget",
|
|
75
|
+
"",
|
|
76
|
+
`- Daily task-credit budget: ${Number(input.summary.dailyTaskCreditBudget ?? 0)}`,
|
|
77
|
+
`- Used task credits: ${Number(input.summary.usedTaskCredits ?? 0)}`,
|
|
78
|
+
`- Remaining task credits: ${Number(input.summary.remainingTaskCredits ?? 0)}`,
|
|
79
|
+
`- Credit ledger entries: ${Number(input.summary.creditLedgerEntries ?? 0)}`,
|
|
80
|
+
"",
|
|
81
|
+
"## Priority Plan",
|
|
82
|
+
"",
|
|
83
|
+
renderPriorityItems(input.prioritySnapshot).trimEnd(),
|
|
84
|
+
"",
|
|
85
|
+
"## Tasks",
|
|
86
|
+
"",
|
|
87
|
+
renderTasks(input.tasks).trimEnd(),
|
|
88
|
+
"",
|
|
89
|
+
"## Changed Files",
|
|
90
|
+
"",
|
|
91
|
+
renderChangedFiles(input.changedFiles).trimEnd(),
|
|
92
|
+
"",
|
|
93
|
+
"## Releases",
|
|
94
|
+
"",
|
|
95
|
+
renderReleases(input.releases).trimEnd(),
|
|
96
|
+
"",
|
|
97
|
+
"## Final Status",
|
|
98
|
+
"",
|
|
99
|
+
`- Workday state: ${String(input.workDay.state ?? "completed")}`,
|
|
100
|
+
`- Desired workers: ${Number(input.scaleDecision.desiredWorkers ?? 0)}`,
|
|
101
|
+
`- Queue depth at report: ${Number(input.scaleDecision.observedQueueDepth ?? 0)}`,
|
|
102
|
+
`- Active leases at report: ${Number(input.scaleDecision.observedActiveLeases ?? 0)}`,
|
|
103
|
+
`- Scale provider: ${input.scaleResult.provider}`,
|
|
104
|
+
""
|
|
105
|
+
].join("\n");
|
|
106
|
+
}
|
|
107
|
+
function writeWorkdayContentSnapshot(input) {
|
|
108
|
+
const outputRoot = resolve(input.repoRoot, "src/content/workdays");
|
|
109
|
+
mkdirSync(outputRoot, { recursive: true });
|
|
110
|
+
const workDayId = String(input.workDay.id ?? "workday");
|
|
111
|
+
const startedAt = toIsoDate(input.workDay.startedAt ?? input.workDay.started_at) ?? input.generatedAt;
|
|
112
|
+
const endedAt = toIsoDate(input.workDay.endedAt ?? input.workDay.ended_at);
|
|
113
|
+
const generatedAt = toIsoDate(input.generatedAt) ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
114
|
+
const datePart = (startedAt || generatedAt).slice(0, 10);
|
|
115
|
+
const slugBase = `${datePart}/${sanitizeSegment(workDayId, "workday")}`;
|
|
116
|
+
const identityHash = stableHash(JSON.stringify({
|
|
117
|
+
workDayId,
|
|
118
|
+
generatedAt,
|
|
119
|
+
summary: input.summary,
|
|
120
|
+
changedFiles: input.changedFiles,
|
|
121
|
+
releases: input.releases
|
|
122
|
+
})).slice(0, 8);
|
|
123
|
+
const reportVersion = `${compactTimestamp(generatedAt)}-${identityHash}`;
|
|
124
|
+
const title = `Workday ${workDayId} Report ${generatedAt.slice(0, 10)}`;
|
|
125
|
+
const slug = `workdays/${slugBase}/${reportVersion}`;
|
|
126
|
+
const frontmatter = {
|
|
127
|
+
title,
|
|
128
|
+
slug,
|
|
129
|
+
workDayId,
|
|
130
|
+
reportVersion,
|
|
131
|
+
reportKind: "workday_summary",
|
|
132
|
+
projectId: input.projectId,
|
|
133
|
+
teamId: input.teamId,
|
|
134
|
+
environment: input.environment,
|
|
135
|
+
status: "live",
|
|
136
|
+
visibility: "team",
|
|
137
|
+
workdayState: String(input.workDay.state ?? "completed"),
|
|
138
|
+
startedAt,
|
|
139
|
+
endedAt,
|
|
140
|
+
generatedAt,
|
|
141
|
+
createdAt: generatedAt,
|
|
142
|
+
summary: bodySummary(input.summary),
|
|
143
|
+
dailyTaskCreditBudget: Number(input.summary.dailyTaskCreditBudget ?? 0),
|
|
144
|
+
usedTaskCredits: Number(input.summary.usedTaskCredits ?? 0),
|
|
145
|
+
remainingTaskCredits: Number(input.summary.remainingTaskCredits ?? 0),
|
|
146
|
+
creditLedgerEntries: Number(input.summary.creditLedgerEntries ?? 0),
|
|
147
|
+
prioritySnapshotId: input.prioritySnapshot?.id ?? null,
|
|
148
|
+
priorityItemCount: input.prioritySnapshot?.items.length ?? 0,
|
|
149
|
+
priorityItems: input.prioritySnapshot?.items ?? [],
|
|
150
|
+
totalTasks: Number(input.summary.totalTasks ?? input.tasks.length),
|
|
151
|
+
completedTasks: Number(input.summary.completedTasks ?? 0),
|
|
152
|
+
failedTasks: Number(input.summary.failedTasks ?? 0),
|
|
153
|
+
queuedTasks: Number(input.summary.queuedTasks ?? 0),
|
|
154
|
+
activeTasks: Number(input.summary.activeTasks ?? 0),
|
|
155
|
+
taskItems: input.tasks,
|
|
156
|
+
changedFiles: input.changedFiles,
|
|
157
|
+
releases: input.releases,
|
|
158
|
+
scaleDecision: input.scaleDecision,
|
|
159
|
+
scaleResult: input.scaleResult,
|
|
160
|
+
metadata: {
|
|
161
|
+
source: "manager",
|
|
162
|
+
projectId: input.projectId
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
const markdownBody = buildMarkdownBody(input);
|
|
166
|
+
let fileName = `${datePart}-${sanitizeSegment(workDayId, "workday")}--${reportVersion}.mdx`;
|
|
167
|
+
let filePath = resolve(outputRoot, fileName);
|
|
168
|
+
let duplicateCounter = 1;
|
|
169
|
+
while (existsSync(filePath)) {
|
|
170
|
+
fileName = `${datePart}-${sanitizeSegment(workDayId, "workday")}--${reportVersion}-${duplicateCounter}.mdx`;
|
|
171
|
+
filePath = resolve(outputRoot, fileName);
|
|
172
|
+
duplicateCounter += 1;
|
|
173
|
+
}
|
|
174
|
+
const document = `---
|
|
175
|
+
${stringifyYaml(frontmatter).trimEnd()}
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
${markdownBody}`;
|
|
179
|
+
writeFileSync(filePath, document, "utf8");
|
|
180
|
+
return {
|
|
181
|
+
filePath,
|
|
182
|
+
relativePath: relative(input.repoRoot, filePath).replaceAll("\\", "/"),
|
|
183
|
+
slug,
|
|
184
|
+
reportVersion,
|
|
185
|
+
title
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
export {
|
|
189
|
+
writeWorkdayContentSnapshot
|
|
190
|
+
};
|
|
@@ -1,17 +1,175 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
export declare function runWorkdayReport(): Promise<{
|
|
3
|
+
ok: boolean;
|
|
4
|
+
mode: "reconcile";
|
|
5
|
+
managerId: string;
|
|
6
|
+
projectId: string;
|
|
7
|
+
environment: "local" | "prod" | "staging";
|
|
8
|
+
insideWorkWindow: boolean;
|
|
9
|
+
workPolicy: import("@treeseed/sdk").WorkdayPolicy;
|
|
10
|
+
workDay: Record<string, unknown>;
|
|
11
|
+
prioritySnapshot: import("@treeseed/sdk").PrioritySnapshot;
|
|
12
|
+
seededTasks: {
|
|
13
|
+
[x: string]: unknown;
|
|
14
|
+
}[];
|
|
15
|
+
queuedCount: number;
|
|
16
|
+
activeLeases: number;
|
|
17
|
+
desiredWorkers: number;
|
|
18
|
+
scaleResult: import("@treeseed/sdk").WorkerPoolScaleResult;
|
|
19
|
+
workdaySummary: Record<string, unknown>;
|
|
20
|
+
} | {
|
|
21
|
+
ok: boolean;
|
|
22
|
+
created: boolean;
|
|
23
|
+
workDay: Record<string, unknown>;
|
|
24
|
+
skipped?: undefined;
|
|
25
|
+
reason?: undefined;
|
|
26
|
+
prioritySnapshot?: undefined;
|
|
27
|
+
} | {
|
|
28
|
+
ok: boolean;
|
|
29
|
+
created: boolean;
|
|
30
|
+
skipped: boolean;
|
|
31
|
+
reason: string;
|
|
32
|
+
workDay?: undefined;
|
|
33
|
+
prioritySnapshot?: undefined;
|
|
34
|
+
} | {
|
|
35
|
+
ok: boolean;
|
|
36
|
+
created: boolean;
|
|
37
|
+
workDay: import("@treeseed/sdk").SdkWorkDayEntity;
|
|
38
|
+
prioritySnapshot: import("@treeseed/sdk").PrioritySnapshot;
|
|
39
|
+
skipped?: undefined;
|
|
40
|
+
reason?: undefined;
|
|
41
|
+
} | {
|
|
42
|
+
ok: boolean;
|
|
43
|
+
skipped: boolean;
|
|
44
|
+
reason: string;
|
|
45
|
+
workDay?: undefined;
|
|
46
|
+
summary?: undefined;
|
|
47
|
+
scale?: undefined;
|
|
48
|
+
} | {
|
|
49
|
+
ok: boolean;
|
|
50
|
+
workDay: import("@treeseed/sdk").SdkWorkDayEntity;
|
|
51
|
+
summary: {
|
|
52
|
+
contentSnapshot: {
|
|
53
|
+
relativePath: string;
|
|
54
|
+
slug: string;
|
|
55
|
+
reportVersion: string;
|
|
56
|
+
title: string;
|
|
57
|
+
};
|
|
58
|
+
projectId: string;
|
|
59
|
+
environment: "local" | "prod" | "staging";
|
|
60
|
+
workDayId: string;
|
|
61
|
+
state: string;
|
|
62
|
+
totalTasks: number;
|
|
63
|
+
completedTasks: number;
|
|
64
|
+
failedTasks: number;
|
|
65
|
+
queuedTasks: number;
|
|
66
|
+
activeTasks: number;
|
|
67
|
+
dailyTaskCreditBudget: number;
|
|
68
|
+
usedTaskCredits: number;
|
|
69
|
+
remainingTaskCredits: number;
|
|
70
|
+
creditLedgerEntries: number;
|
|
71
|
+
prioritySnapshotId: string;
|
|
72
|
+
priorityItemCount: number;
|
|
73
|
+
priorityItems: import("@treeseed/sdk").PrioritySnapshotItem[];
|
|
74
|
+
taskItems: {
|
|
75
|
+
id: string;
|
|
76
|
+
agentId: string;
|
|
77
|
+
type: string;
|
|
78
|
+
state: string;
|
|
79
|
+
priority: number;
|
|
80
|
+
idempotencyKey: string;
|
|
81
|
+
createdAt: string;
|
|
82
|
+
startedAt: string;
|
|
83
|
+
completedAt: string;
|
|
84
|
+
lastErrorCode: string;
|
|
85
|
+
lastErrorMessage: string;
|
|
86
|
+
lastEventKind: string;
|
|
87
|
+
outputCount: number;
|
|
88
|
+
changedFiles: string[];
|
|
89
|
+
}[];
|
|
90
|
+
changedFiles: string[];
|
|
91
|
+
releases: {
|
|
92
|
+
id: string;
|
|
93
|
+
deploymentKind: string;
|
|
94
|
+
status: string;
|
|
95
|
+
releaseTag: string;
|
|
96
|
+
commitSha: string;
|
|
97
|
+
sourceRef: string;
|
|
98
|
+
startedAt: string;
|
|
99
|
+
finishedAt: string;
|
|
100
|
+
createdAt: string;
|
|
101
|
+
}[];
|
|
102
|
+
scaleDecision: import("@treeseed/sdk").ScaleDecision;
|
|
103
|
+
scaleResult: import("@treeseed/sdk").WorkerPoolScaleResult;
|
|
104
|
+
generatedAt: string;
|
|
105
|
+
};
|
|
106
|
+
scale: import("@treeseed/sdk").WorkerPoolScaleResult;
|
|
107
|
+
skipped?: undefined;
|
|
108
|
+
reason?: undefined;
|
|
109
|
+
} | {
|
|
3
110
|
ok: boolean;
|
|
4
111
|
skipped: boolean;
|
|
112
|
+
reason: string;
|
|
5
113
|
workDayId?: undefined;
|
|
6
114
|
summary?: undefined;
|
|
7
115
|
} | {
|
|
8
116
|
ok: boolean;
|
|
9
|
-
workDayId:
|
|
117
|
+
workDayId: unknown;
|
|
10
118
|
summary: {
|
|
119
|
+
contentSnapshot: {
|
|
120
|
+
relativePath: string;
|
|
121
|
+
slug: string;
|
|
122
|
+
reportVersion: string;
|
|
123
|
+
title: string;
|
|
124
|
+
};
|
|
125
|
+
projectId: string;
|
|
126
|
+
environment: "local" | "prod" | "staging";
|
|
127
|
+
workDayId: string;
|
|
128
|
+
state: string;
|
|
11
129
|
totalTasks: number;
|
|
12
130
|
completedTasks: number;
|
|
13
131
|
failedTasks: number;
|
|
14
|
-
|
|
132
|
+
queuedTasks: number;
|
|
133
|
+
activeTasks: number;
|
|
134
|
+
dailyTaskCreditBudget: number;
|
|
135
|
+
usedTaskCredits: number;
|
|
136
|
+
remainingTaskCredits: number;
|
|
137
|
+
creditLedgerEntries: number;
|
|
138
|
+
prioritySnapshotId: string;
|
|
139
|
+
priorityItemCount: number;
|
|
140
|
+
priorityItems: import("@treeseed/sdk").PrioritySnapshotItem[];
|
|
141
|
+
taskItems: {
|
|
142
|
+
id: string;
|
|
143
|
+
agentId: string;
|
|
144
|
+
type: string;
|
|
145
|
+
state: string;
|
|
146
|
+
priority: number;
|
|
147
|
+
idempotencyKey: string;
|
|
148
|
+
createdAt: string;
|
|
149
|
+
startedAt: string;
|
|
150
|
+
completedAt: string;
|
|
151
|
+
lastErrorCode: string;
|
|
152
|
+
lastErrorMessage: string;
|
|
153
|
+
lastEventKind: string;
|
|
154
|
+
outputCount: number;
|
|
155
|
+
changedFiles: string[];
|
|
156
|
+
}[];
|
|
157
|
+
changedFiles: string[];
|
|
158
|
+
releases: {
|
|
159
|
+
id: string;
|
|
160
|
+
deploymentKind: string;
|
|
161
|
+
status: string;
|
|
162
|
+
releaseTag: string;
|
|
163
|
+
commitSha: string;
|
|
164
|
+
sourceRef: string;
|
|
165
|
+
startedAt: string;
|
|
166
|
+
finishedAt: string;
|
|
167
|
+
createdAt: string;
|
|
168
|
+
}[];
|
|
169
|
+
scaleDecision: import("@treeseed/sdk").ScaleDecision;
|
|
170
|
+
scaleResult: import("@treeseed/sdk").WorkerPoolScaleResult;
|
|
171
|
+
generatedAt: string;
|
|
15
172
|
};
|
|
16
173
|
skipped?: undefined;
|
|
174
|
+
reason?: undefined;
|
|
17
175
|
}>;
|
|
@@ -1,37 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import {
|
|
3
|
+
import { runManagerAction } from "./manager.js";
|
|
4
4
|
async function runWorkdayReport() {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const active = workDays.payload[0];
|
|
9
|
-
if (!active || typeof active.id !== "string") {
|
|
10
|
-
return { ok: true, skipped: true };
|
|
11
|
-
}
|
|
12
|
-
const tasks = await sdk.searchTasks({ workDayId: active.id, limit: 200 });
|
|
13
|
-
const summary = {
|
|
14
|
-
totalTasks: tasks.payload.length,
|
|
15
|
-
completedTasks: tasks.payload.filter((entry) => entry.state === "completed").length,
|
|
16
|
-
failedTasks: tasks.payload.filter((entry) => entry.state === "failed").length,
|
|
17
|
-
pendingTasks: tasks.payload.filter((entry) => entry.state !== "completed" && entry.state !== "failed").length
|
|
18
|
-
};
|
|
19
|
-
if (gateway) {
|
|
20
|
-
await gateway.requestJson("/reports", {
|
|
21
|
-
body: {
|
|
22
|
-
workDayId: active.id,
|
|
23
|
-
kind: "workday_summary",
|
|
24
|
-
body: summary
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
await gateway.requestJson(`/workdays/${encodeURIComponent(active.id)}/close`, {
|
|
28
|
-
body: {
|
|
29
|
-
state: "completed",
|
|
30
|
-
summary
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
return { ok: true, workDayId: active.id, summary };
|
|
5
|
+
return runManagerAction({
|
|
6
|
+
mode: "report-workday"
|
|
7
|
+
});
|
|
35
8
|
}
|
|
36
9
|
const currentFile = fileURLToPath(import.meta.url);
|
|
37
10
|
const entryFile = process.argv[1] ?? "";
|