fix(skills): pull upstream skill runtime resolution to stop event-loop starvation
Build: Production / build (push) Failing after 12m39s
Build: Production / build (push) Failing after 12m39s
The fork's listRuntimeSkillEntries rematerialized every skill's files from the DB on every heartbeat run dispatch — fs.rm + fs.mkdir + per-file readFile/writeFile, sequentially per skill. With 24 configured skills and 5 concurrent agents, this saturated the Node event loop badly enough that executeRun continuations couldn't reach activeRunExecutions.add() within the orphan-reaper's 5-min threshold, causing reaper to false-positive runs as "process_lost". Upstream's listRuntimeSkillEntries calls resolveRuntimeSkillSource, which checks if the materialized directory already exists on disk and short- circuits when it does. Fixes the symptom at the root. Replaces these files with upstream/master content: - server/src/services/company-skills.ts - server/src/services/heartbeat.ts - server/src/services/workspace-runtime.ts - server/src/services/company-portability.ts - server/src/routes/company-skills.ts - server/src/routes/agents.ts - packages/adapter-utils/src/server-utils.ts Pulls in supporting upstream files: - server/src/services/catalog-provenance.ts - server/src/services/skills-catalog.ts - server/src/services/github-fetch.ts - server/src/services/portable-path.ts - packages/skills-catalog/ (new package) - packages/db document_annotation_* schema + migration 0091 - packages/shared document-annotation types/validators Drops fork features (to be re-evaluated later): - Gitea/Forgejo git skill sources (server/src/services/git-source.ts deleted) - PAT support for private skill repos - Fork-specific secret-export portability extensions Adds agentId: null to acquireRunLease test-probe call in routes/agents.ts to satisfy the fork's environment-runtime agentId requirement (kept). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -35,6 +35,10 @@ export const companySkillListItemSchema = companySkillSchema.extend({
|
||||
editableReason: z.string().nullable(),
|
||||
sourceLabel: z.string().nullable(),
|
||||
sourceBadge: companySkillSourceBadgeSchema,
|
||||
catalogKind: z.enum(["bundled", "optional"]).nullable(),
|
||||
originHash: z.string().nullable(),
|
||||
packageName: z.string().nullable(),
|
||||
packageVersion: z.string().nullable(),
|
||||
});
|
||||
|
||||
export const companySkillUsageAgentSchema = z.object({
|
||||
@@ -64,15 +68,48 @@ export const companySkillUpdateStatusSchema = z.object({
|
||||
currentRef: z.string().nullable(),
|
||||
latestRef: z.string().nullable(),
|
||||
hasUpdate: z.boolean(),
|
||||
installedHash: z.string().nullable(),
|
||||
originHash: z.string().nullable(),
|
||||
userModifiedAt: z.string().nullable(),
|
||||
updateHoldReason: z.enum([
|
||||
"local_modifications",
|
||||
"audit_hard_stop",
|
||||
"origin_unavailable",
|
||||
"compatibility_invalid",
|
||||
"operator_hold",
|
||||
]).nullable(),
|
||||
auditVerdict: z.enum(["pass", "warning", "fail"]).nullable(),
|
||||
auditCodes: z.array(z.string()),
|
||||
});
|
||||
|
||||
export const companySkillAuditFindingSchema = z.object({
|
||||
code: z.string().min(1),
|
||||
severity: z.enum(["warning", "error"]),
|
||||
message: z.string().min(1),
|
||||
path: z.string().nullable(),
|
||||
});
|
||||
|
||||
export const companySkillAuditResultSchema = z.object({
|
||||
skillId: z.string().uuid(),
|
||||
installedHash: z.string().nullable(),
|
||||
originHash: z.string().nullable(),
|
||||
verdict: z.enum(["pass", "warning", "fail"]),
|
||||
codes: z.array(z.string()),
|
||||
findings: z.array(companySkillAuditFindingSchema),
|
||||
scannedAt: z.string().min(1),
|
||||
scanVersion: z.string().min(1),
|
||||
});
|
||||
|
||||
export const companySkillInstallUpdateSchema = z.object({
|
||||
force: z.boolean().optional(),
|
||||
}).default({});
|
||||
|
||||
export const companySkillResetSchema = z.object({
|
||||
force: z.boolean().optional(),
|
||||
}).default({});
|
||||
|
||||
export const companySkillImportSchema = z.object({
|
||||
source: z.string().min(1),
|
||||
authToken: z.string().min(1).optional(),
|
||||
});
|
||||
|
||||
export const companySkillUpdateAuthSchema = z.object({
|
||||
authToken: z.string().min(1).nullable(),
|
||||
});
|
||||
|
||||
export const companySkillProjectScanRequestSchema = z.object({
|
||||
@@ -136,8 +173,70 @@ export const companySkillFileUpdateSchema = z.object({
|
||||
content: z.string(),
|
||||
});
|
||||
|
||||
export const catalogSkillKindSchema = z.enum(["bundled", "optional"]);
|
||||
|
||||
export const catalogSkillFileSchema = z.object({
|
||||
path: z.string().min(1),
|
||||
kind: z.enum(["skill", "markdown", "reference", "script", "asset", "other"]),
|
||||
sizeBytes: z.number().int().nonnegative(),
|
||||
sha256: z.string().min(1),
|
||||
});
|
||||
|
||||
export const catalogSkillSchema = z.object({
|
||||
id: z.string().min(1),
|
||||
key: z.string().min(1),
|
||||
kind: catalogSkillKindSchema,
|
||||
category: z.string().min(1),
|
||||
slug: z.string().min(1),
|
||||
name: z.string().min(1),
|
||||
description: z.string(),
|
||||
path: z.string().min(1),
|
||||
entrypoint: z.literal("SKILL.md"),
|
||||
trustLevel: companySkillTrustLevelSchema,
|
||||
compatibility: companySkillCompatibilitySchema,
|
||||
defaultInstall: z.boolean(),
|
||||
recommendedForRoles: z.array(z.string()),
|
||||
requires: z.array(z.string()),
|
||||
tags: z.array(z.string()),
|
||||
files: z.array(catalogSkillFileSchema),
|
||||
contentHash: z.string().min(1),
|
||||
packageName: z.string().min(1).optional(),
|
||||
packageVersion: z.string().min(1).optional(),
|
||||
});
|
||||
|
||||
export const catalogSkillListQuerySchema = z.object({
|
||||
kind: catalogSkillKindSchema.optional(),
|
||||
category: z.string().min(1).optional(),
|
||||
q: z.string().min(1).optional(),
|
||||
});
|
||||
|
||||
export const catalogSkillFileDetailSchema = z.object({
|
||||
catalogSkillId: z.string().min(1),
|
||||
path: z.string().min(1),
|
||||
kind: z.enum(["skill", "markdown", "reference", "script", "asset", "other"]),
|
||||
content: z.string(),
|
||||
language: z.string().nullable(),
|
||||
markdown: z.boolean(),
|
||||
});
|
||||
|
||||
export const companySkillInstallCatalogSchema = z.object({
|
||||
catalogSkillId: z.string().min(1),
|
||||
slug: z.string().min(1).nullable().optional(),
|
||||
force: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export const companySkillInstallCatalogResultSchema = z.object({
|
||||
action: z.enum(["created", "updated", "unchanged"]),
|
||||
skill: companySkillSchema,
|
||||
catalogSkill: catalogSkillSchema,
|
||||
warnings: z.array(z.string()),
|
||||
});
|
||||
|
||||
export type CompanySkillImport = z.infer<typeof companySkillImportSchema>;
|
||||
export type CompanySkillProjectScan = z.infer<typeof companySkillProjectScanRequestSchema>;
|
||||
export type CompanySkillCreate = z.infer<typeof companySkillCreateSchema>;
|
||||
export type CompanySkillFileUpdate = z.infer<typeof companySkillFileUpdateSchema>;
|
||||
export type CompanySkillUpdateAuth = z.infer<typeof companySkillUpdateAuthSchema>;
|
||||
export type CatalogSkillListQuery = z.infer<typeof catalogSkillListQuerySchema>;
|
||||
export type CompanySkillInstallCatalog = z.infer<typeof companySkillInstallCatalogSchema>;
|
||||
export type CompanySkillInstallUpdate = z.infer<typeof companySkillInstallUpdateSchema>;
|
||||
export type CompanySkillReset = z.infer<typeof companySkillResetSchema>;
|
||||
|
||||
Reference in New Issue
Block a user