@cat-kit/agent-context 1.1.3 → 1.1.4
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/dist/commands/status.js +1 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/validate.js +1 -1
- package/dist/commands/validate.js.map +1 -1
- package/dist/context/reader.js +1 -1
- package/dist/context/reader.js.map +1 -1
- package/dist/context/validator.js +1 -1
- package/dist/context/validator.js.map +1 -1
- package/dist/stats.html +1 -1
- package/package.json +2 -2
- package/src/commands/status.ts +7 -9
- package/src/commands/validate.ts +6 -6
- package/src/context/reader.ts +32 -9
- package/src/context/validator.ts +19 -0
- package/src/types.ts +2 -2
package/dist/commands/status.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{readRawContext as e}from"../context/reader.js";import{validate as t}from"../context/validator.js";async function n(){let{snapshot:n,currentPlanCount:r}=await e(process.cwd()),i=t(n,r);if(!i.valid){for(let e of i.errors)console.log(`❌ ${e}`);process.exitCode=1;return}if(i.context===null){console.log(`ℹ 无活跃上下文`);return}let a=i.context,o=a.currentPlan?`plan-${a.currentPlan.number} (${a.currentPlan.status})`:`无`,s=a.preparing.length>0?a.preparing.map(e=>`plan-${e.number}`).join(`, `):`无`;console.log(``),console.log(`Agent Context Status`),console.log(`────────────────────`),console.log(`当前计划: ${o}`),console.log(`待执行队列: ${s}`),console.log(`已归档: ${a.
|
|
1
|
+
import{readRawContext as e}from"../context/reader.js";import{validate as t}from"../context/validator.js";async function n(){let{snapshot:n,currentPlanCount:r}=await e(process.cwd()),i=t(n,r);if(!i.valid){for(let e of i.errors)console.log(`❌ ${e}`);process.exitCode=1;return}if(i.context===null){console.log(`ℹ 无活跃上下文`);return}let a=i.context,o=a.currentPlan?`plan-${a.currentPlan.number} (${a.currentPlan.status})`:`无`,s=a.preparing.length>0?a.preparing.map(e=>`plan-${e.number}`).join(`, `):`无`;console.log(``),console.log(`Agent Context Status`),console.log(`────────────────────`),console.log(`当前计划: ${o}`),console.log(`待执行队列: ${s}`),console.log(`已归档: ${a.done.length} 个`)}export{n as statusCommand};
|
|
2
2
|
//# sourceMappingURL=status.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","names":[],"sources":["../../src/commands/status.ts"],"sourcesContent":["import { readRawContext, validate } from '../context/index.js'\n\nexport async function statusCommand(): Promise<void> {\n const { snapshot, currentPlanCount } = await readRawContext(process.cwd())\n const result = validate(snapshot, currentPlanCount)\n\n if (!result.valid) {\n for (const error of result.errors) {\n console.log(`❌ ${error}`) // eslint-disable-line no-console\n }\n process.exitCode = 1\n return\n }\n\n if (result.context === null) {\n console.log('ℹ 无活跃上下文') // eslint-disable-line no-console\n return\n }\n\n const ctx = result.context\n const current = ctx.currentPlan\n ? `plan-${ctx.currentPlan.number} (${ctx.currentPlan.status})`\n : '无'\n const preparing =\n ctx.preparing.length > 0
|
|
1
|
+
{"version":3,"file":"status.js","names":[],"sources":["../../src/commands/status.ts"],"sourcesContent":["import { readRawContext, validate } from '../context/index.js'\n\nexport async function statusCommand(): Promise<void> {\n const { snapshot, currentPlanCount } = await readRawContext(process.cwd())\n const result = validate(snapshot, currentPlanCount)\n\n if (!result.valid) {\n for (const error of result.errors) {\n console.log(`❌ ${error}`) // eslint-disable-line no-console\n }\n process.exitCode = 1\n return\n }\n\n if (result.context === null) {\n console.log('ℹ 无活跃上下文') // eslint-disable-line no-console\n return\n }\n\n const ctx = result.context\n const current = ctx.currentPlan\n ? `plan-${ctx.currentPlan.number} (${ctx.currentPlan.status})`\n : '无'\n const preparing =\n ctx.preparing.length > 0 ? ctx.preparing.map((p) => `plan-${p.number}`).join(', ') : '无'\n\n console.log('')\n console.log('Agent Context Status')\n console.log('────────────────────')\n console.log(`当前计划: ${current}`)\n console.log(`待执行队列: ${preparing}`)\n console.log(`已归档: ${ctx.done.length} 个`)\n}\n"],"mappings":"yGAEA,eAAsB,GAA+B,CACnD,GAAM,CAAE,WAAU,oBAAqB,MAAM,EAAe,QAAQ,KAAK,CAAC,CACpE,EAAS,EAAS,EAAU,EAAiB,CAEnD,GAAI,CAAC,EAAO,MAAO,CACjB,IAAK,IAAM,KAAS,EAAO,OACzB,QAAQ,IAAI,KAAK,IAAQ,CAE3B,QAAQ,SAAW,EACnB,OAGF,GAAI,EAAO,UAAY,KAAM,CAC3B,QAAQ,IAAI,WAAW,CACvB,OAGF,IAAM,EAAM,EAAO,QACb,EAAU,EAAI,YAChB,QAAQ,EAAI,YAAY,OAAO,IAAI,EAAI,YAAY,OAAO,GAC1D,IACE,EACJ,EAAI,UAAU,OAAS,EAAI,EAAI,UAAU,IAAK,GAAM,QAAQ,EAAE,SAAS,CAAC,KAAK,KAAK,CAAG,IAEvF,QAAQ,IAAI,GAAG,CACf,QAAQ,IAAI,uBAAuB,CACnC,QAAQ,IAAI,uBAAuB,CACnC,QAAQ,IAAI,UAAU,IAAU,CAChC,QAAQ,IAAI,UAAU,IAAY,CAClC,QAAQ,IAAI,WAAW,EAAI,KAAK,OAAO,IAAI"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{readRawContext as e}from"../context/reader.js";import{validate as t}from"../context/validator.js";async function n(){let{snapshot:n,currentPlanCount:r}=await e(process.cwd()),i=t(n,r);if(i.context===null){console.log(
|
|
1
|
+
import{readRawContext as e}from"../context/reader.js";import{validate as t}from"../context/validator.js";async function n(){let{snapshot:n,currentPlanCount:r}=await e(process.cwd()),i=t(n,r);if(i.context===null){console.log(`⚠️ 无 .agent-context 目录`);return}if(i.valid){console.log(`✅ 校验通过`);let e=i.context,t=e.currentPlan?`plan-${e.currentPlan.number} (${e.currentPlan.status})`:`无`;console.log(` 当前计划: ${t}`),console.log(` 待执行: ${e.preparing.length} 个`),console.log(` 已归档: ${e.done.length} 个`);return}for(let e of i.errors)console.log(`❌ ${e}`);process.exitCode=1}export{n as validateCommand};
|
|
2
2
|
//# sourceMappingURL=validate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","names":[],"sources":["../../src/commands/validate.ts"],"sourcesContent":["import { readRawContext, validate } from '../context/index.js'\n\nexport async function validateCommand(): Promise<void> {\n const { snapshot, currentPlanCount } = await readRawContext(process.cwd())\n const result = validate(snapshot, currentPlanCount)\n\n if (result.context === null) {\n console.log('
|
|
1
|
+
{"version":3,"file":"validate.js","names":[],"sources":["../../src/commands/validate.ts"],"sourcesContent":["import { readRawContext, validate } from '../context/index.js'\n\nexport async function validateCommand(): Promise<void> {\n const { snapshot, currentPlanCount } = await readRawContext(process.cwd())\n const result = validate(snapshot, currentPlanCount)\n\n if (result.context === null) {\n console.log('⚠️ 无 .agent-context 目录')\n return\n }\n\n if (result.valid) {\n console.log('✅ 校验通过')\n const ctx = result.context\n const current = ctx.currentPlan\n ? `plan-${ctx.currentPlan.number} (${ctx.currentPlan.status})`\n : '无'\n console.log(` 当前计划: ${current}`)\n console.log(` 待执行: ${ctx.preparing.length} 个`)\n console.log(` 已归档: ${ctx.done.length} 个`)\n return\n }\n\n for (const error of result.errors) {\n console.log(`❌ ${error}`)\n }\n process.exitCode = 1\n}\n"],"mappings":"yGAEA,eAAsB,GAAiC,CACrD,GAAM,CAAE,WAAU,oBAAqB,MAAM,EAAe,QAAQ,KAAK,CAAC,CACpE,EAAS,EAAS,EAAU,EAAiB,CAEnD,GAAI,EAAO,UAAY,KAAM,CAC3B,QAAQ,IAAI,yBAAyB,CACrC,OAGF,GAAI,EAAO,MAAO,CAChB,QAAQ,IAAI,SAAS,CACrB,IAAM,EAAM,EAAO,QACb,EAAU,EAAI,YAChB,QAAQ,EAAI,YAAY,OAAO,IAAI,EAAI,YAAY,OAAO,GAC1D,IACJ,QAAQ,IAAI,WAAW,IAAU,CACjC,QAAQ,IAAI,UAAU,EAAI,UAAU,OAAO,IAAI,CAC/C,QAAQ,IAAI,UAAU,EAAI,KAAK,OAAO,IAAI,CAC1C,OAGF,IAAK,IAAM,KAAS,EAAO,OACzB,QAAQ,IAAI,KAAK,IAAQ,CAE3B,QAAQ,SAAW"}
|
package/dist/context/reader.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{existsSync as e}from"node:fs";import{join as t}from"node:path";import{readFile as n,readdir as r}from"node:fs/promises";const i=/^plan-(\d+)$/,a=/^>\s*状态:\s*(未执行|已执行)\
|
|
1
|
+
import{existsSync as e}from"node:fs";import{join as t}from"node:path";import{readFile as n,readdir as r}from"node:fs/promises";const i=/^plan-(\d+)$/,a=/^plan-(\d+)(?:-\d{8})?$/,o=/^>\s*状态:\s*(未执行|已执行)$/m,s=/^>?[ \t]*状态[::].*$/m;async function c(n){let r=t(n,`.agent-context`);if(!e(r))return{snapshot:null,currentPlanCount:0};let i=await u(r),a=await u(t(r,`preparing`)),o=await d(t(r,`done`));return{snapshot:{root:r,currentPlan:i[0]??null,preparing:a,done:o},currentPlanCount:i.length}}async function l(r){let i=t(r,`plan.md`);if(!e(i))return`未执行`;let a=await n(i,`utf-8`),c=a.match(o);return c?c[1]:s.test(a)?`未知`:`未执行`}async function u(n){if(!e(n))return[];let a=await r(n,{withFileTypes:!0}),o=[];for(let e of a){if(!e.isDirectory())continue;let r=e.name.match(i);if(!r?.[1])continue;let a=parseInt(r[1],10),s=t(n,e.name),c=await l(s);o.push({number:a,status:c,dir:s})}return o.sort((e,t)=>e.number-t.number)}async function d(n){if(!e(n))return[];let i=await r(n,{withFileTypes:!0}),o=[];for(let e of i){if(!e.isDirectory())continue;let r=e.name.match(a);r?.[1]&&o.push({number:parseInt(r[1],10),dir:t(n,e.name)})}return o.sort((e,t)=>e.number-t.number)}export{c as readRawContext};
|
|
2
2
|
//# sourceMappingURL=reader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reader.js","names":[],"sources":["../../src/context/reader.ts"],"sourcesContent":["import { readdir, readFile } from 'node:fs/promises'\nimport { existsSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { ContextSnapshot, PlanInfo, PlanStatus } from '../types.js'\n\nconst PLAN_DIR_RE = /^plan-(\\d+)$/\nconst
|
|
1
|
+
{"version":3,"file":"reader.js","names":[],"sources":["../../src/context/reader.ts"],"sourcesContent":["import { readdir, readFile } from 'node:fs/promises'\nimport { existsSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { ContextSnapshot, PlanInfo, PlanStatus } from '../types.js'\n\nconst PLAN_DIR_RE = /^plan-(\\d+)$/\nconst DONE_DIR_RE = /^plan-(\\d+)(?:-\\d{8})?$/\nconst EXACT_STATUS_RE = /^>\\s*状态:\\s*(未执行|已执行)$/m\nconst LOOSE_STATUS_RE = /^>?[ \\t]*状态[::].*$/m\n\n// ── Public API ───────────────────────────────────────\n\nexport async function readContext(cwd: string): Promise<ContextSnapshot | null> {\n const { snapshot } = await readRawContext(cwd)\n return snapshot\n}\n\nexport async function readRawContext(\n cwd: string\n): Promise<{ snapshot: ContextSnapshot | null; currentPlanCount: number }> {\n const root = join(cwd, '.agent-context')\n\n if (!existsSync(root)) {\n return { snapshot: null, currentPlanCount: 0 }\n }\n\n const currentPlans = await readPlanDirs(root)\n const preparing = await readPlanDirs(join(root, 'preparing'))\n const done = await readDonePlans(join(root, 'done'))\n\n const snapshot: ContextSnapshot = {\n root,\n currentPlan: currentPlans[0] ?? null,\n preparing,\n done\n }\n\n return { snapshot, currentPlanCount: currentPlans.length }\n}\n\nexport async function readPlanStatus(planDir: string): Promise<PlanStatus> {\n const planFile = join(planDir, 'plan.md')\n\n if (!existsSync(planFile)) {\n return '未执行'\n }\n\n const content = await readFile(planFile, 'utf-8')\n \n const exactMatch = content.match(EXACT_STATUS_RE)\n if (exactMatch) {\n return exactMatch[1] as PlanStatus\n }\n\n if (LOOSE_STATUS_RE.test(content)) {\n return '未知'\n }\n\n return '未执行'\n}\n\n// ── Helpers ──────────────────────────────────────────\n\nasync function readPlanDirs(parentDir: string): Promise<PlanInfo[]> {\n if (!existsSync(parentDir)) return []\n\n const entries = await readdir(parentDir, { withFileTypes: true })\n const plans: PlanInfo[] = []\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue\n const match = entry.name.match(PLAN_DIR_RE)\n if (!match?.[1]) continue\n const number = parseInt(match[1], 10)\n const dir = join(parentDir, entry.name)\n const status = await readPlanStatus(dir)\n plans.push({ number, status, dir })\n }\n\n return plans.sort((a, b) => a.number - b.number)\n}\n\nasync function readDonePlans(parentDir: string): Promise<Pick<PlanInfo, 'number' | 'dir'>[]> {\n if (!existsSync(parentDir)) return []\n const entries = await readdir(parentDir, { withFileTypes: true })\n const plans: Pick<PlanInfo, 'number' | 'dir'>[] = []\n \n for (const entry of entries) {\n if (!entry.isDirectory()) continue\n const match = entry.name.match(DONE_DIR_RE)\n if (!match?.[1]) continue\n plans.push({\n number: parseInt(match[1], 10),\n dir: join(parentDir, entry.name)\n })\n }\n\n return plans.sort((a, b) => a.number - b.number)\n}\n"],"mappings":"+HAMA,MAAM,EAAc,eACd,EAAc,0BACd,EAAkB,yBAClB,EAAkB,sBASxB,eAAsB,EACpB,EACyE,CACzE,IAAM,EAAO,EAAK,EAAK,iBAAiB,CAExC,GAAI,CAAC,EAAW,EAAK,CACnB,MAAO,CAAE,SAAU,KAAM,iBAAkB,EAAG,CAGhD,IAAM,EAAe,MAAM,EAAa,EAAK,CACvC,EAAY,MAAM,EAAa,EAAK,EAAM,YAAY,CAAC,CACvD,EAAO,MAAM,EAAc,EAAK,EAAM,OAAO,CAAC,CASpD,MAAO,CAAE,SAPyB,CAChC,OACA,YAAa,EAAa,IAAM,KAChC,YACA,OACD,CAEkB,iBAAkB,EAAa,OAAQ,CAG5D,eAAsB,EAAe,EAAsC,CACzE,IAAM,EAAW,EAAK,EAAS,UAAU,CAEzC,GAAI,CAAC,EAAW,EAAS,CACvB,MAAO,MAGT,IAAM,EAAU,MAAM,EAAS,EAAU,QAAQ,CAE3C,EAAa,EAAQ,MAAM,EAAgB,CASjD,OARI,EACK,EAAW,GAGhB,EAAgB,KAAK,EAAQ,CACxB,KAGF,MAKT,eAAe,EAAa,EAAwC,CAClE,GAAI,CAAC,EAAW,EAAU,CAAE,MAAO,EAAE,CAErC,IAAM,EAAU,MAAM,EAAQ,EAAW,CAAE,cAAe,GAAM,CAAC,CAC3D,EAAoB,EAAE,CAE5B,IAAK,IAAM,KAAS,EAAS,CAC3B,GAAI,CAAC,EAAM,aAAa,CAAE,SAC1B,IAAM,EAAQ,EAAM,KAAK,MAAM,EAAY,CAC3C,GAAI,CAAC,IAAQ,GAAI,SACjB,IAAM,EAAS,SAAS,EAAM,GAAI,GAAG,CAC/B,EAAM,EAAK,EAAW,EAAM,KAAK,CACjC,EAAS,MAAM,EAAe,EAAI,CACxC,EAAM,KAAK,CAAE,SAAQ,SAAQ,MAAK,CAAC,CAGrC,OAAO,EAAM,MAAM,EAAG,IAAM,EAAE,OAAS,EAAE,OAAO,CAGlD,eAAe,EAAc,EAAgE,CAC3F,GAAI,CAAC,EAAW,EAAU,CAAE,MAAO,EAAE,CACrC,IAAM,EAAU,MAAM,EAAQ,EAAW,CAAE,cAAe,GAAM,CAAC,CAC3D,EAA4C,EAAE,CAEpD,IAAK,IAAM,KAAS,EAAS,CAC3B,GAAI,CAAC,EAAM,aAAa,CAAE,SAC1B,IAAM,EAAQ,EAAM,KAAK,MAAM,EAAY,CACtC,IAAQ,IACb,EAAM,KAAK,CACT,OAAQ,SAAS,EAAM,GAAI,GAAG,CAC9B,IAAK,EAAK,EAAW,EAAM,KAAK,CACjC,CAAC,CAGJ,OAAO,EAAM,MAAM,EAAG,IAAM,EAAE,OAAS,EAAE,OAAO"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{existsSync as e}from"node:fs";import{join as t}from"node:path";function n(n,r){if(n===null)return{valid:!0,errors:[],context:null};let i=[];r>1&&i.push(`存在 ${r} 个当前计划,应最多 1 个。`),n.currentPlan&&(e(t(n.currentPlan.dir,`plan.md`))||i.push(`当前计划 plan-${n.currentPlan.number} 缺少 plan.md。`));let a=[];n.currentPlan&&a.push(n.currentPlan.number);for(let e of n.preparing)a.push(e.number);let o=new Set,s=new Set;for(let e of a)o.has(e)&&s.add(e),o.add(e);if(s.size>0){let e=[...s].sort((e,t)=>e-t).join(`, `);i.push(`计划编号冲突: ${e}。`)}return{valid:i.length===0,errors:i,context:n}}export{n as validate};
|
|
1
|
+
import{existsSync as e}from"node:fs";import{join as t}from"node:path";function n(n,r){if(n===null)return{valid:!0,errors:[],context:null};let i=[];r>1&&i.push(`存在 ${r} 个当前计划,应最多 1 个。`),n.currentPlan&&(e(t(n.currentPlan.dir,`plan.md`))||i.push(`当前计划 plan-${n.currentPlan.number} 缺少 plan.md。`),n.currentPlan.status===`未知`&&i.push(`当前计划 plan-${n.currentPlan.number} 的状态格式严重不符合要求,请严格按照 "> 状态: 已执行" 或 "> 状态: 未执行" 的格式书写,禁止添加 emoji 或其他额外字符。`));for(let e of n.preparing)e.status===`未知`&&i.push(`待执行计划 plan-${e.number} 的状态格式严重不符合要求,请严格按照 "> 状态: 已执行" 或 "> 状态: 未执行" 的格式书写。`);let a=[];for(let e of n.done)a.push(e.number);n.currentPlan&&a.push(n.currentPlan.number);for(let e of n.preparing)a.push(e.number);let o=new Set,s=new Set;for(let e of a)o.has(e)&&s.add(e),o.add(e);if(s.size>0){let e=[...s].sort((e,t)=>e-t).join(`, `);i.push(`计划编号冲突: ${e}。`)}a.sort((e,t)=>e-t);for(let e=0;e<a.length;e++)if(a[e]!==e+1){i.push(`计划序列不连续或未从 1 开始。预期出现编号 ${e+1},实际遇到编号 ${a[e]} (要求必须是从 1 开始顺序查询)。`);break}return{valid:i.length===0,errors:i,context:n}}export{n as validate};
|
|
2
2
|
//# sourceMappingURL=validator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.js","names":[],"sources":["../../src/context/validator.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { ContextSnapshot, ValidateResult } from '../types.js'\n\nexport function validate(\n snapshot: ContextSnapshot | null,\n currentPlanCount: number\n): ValidateResult {\n if (snapshot === null) {\n return { valid: true, errors: [], context: null }\n }\n\n const errors: string[] = []\n\n if (currentPlanCount > 1) {\n errors.push(`存在 ${currentPlanCount} 个当前计划,应最多 1 个。`)\n }\n\n if (snapshot.currentPlan) {\n const planMd = join(snapshot.currentPlan.dir, 'plan.md')\n if (!existsSync(planMd)) {\n errors.push(`当前计划 plan-${snapshot.currentPlan.number} 缺少 plan.md。`)\n }\n }\n\n const allNumbers: number[] = []\n if (snapshot.currentPlan) allNumbers.push(snapshot.currentPlan.number)\n for (const p of snapshot.preparing) allNumbers.push(p.number)\n\n const seen = new Set<number>()\n const duplicates = new Set<number>()\n for (const n of allNumbers) {\n if (seen.has(n)) duplicates.add(n)\n seen.add(n)\n }\n\n if (duplicates.size > 0) {\n const nums = [...duplicates].sort((a, b) => a - b).join(', ')\n errors.push(`计划编号冲突: ${nums}。`)\n }\n\n return { valid: errors.length === 0, errors, context: snapshot }\n}\n"],"mappings":"sEAKA,SAAgB,EACd,EACA,EACgB,CAChB,GAAI,IAAa,KACf,MAAO,CAAE,MAAO,GAAM,OAAQ,EAAE,CAAE,QAAS,KAAM,CAGnD,IAAM,EAAmB,EAAE,CAEvB,EAAmB,GACrB,EAAO,KAAK,MAAM,EAAiB,iBAAiB,CAGlD,EAAS,cAEN,EADU,EAAK,EAAS,YAAY,IAAK,UAAU,CACjC,EACrB,EAAO,KAAK,aAAa,EAAS,YAAY,OAAO,cAAc,
|
|
1
|
+
{"version":3,"file":"validator.js","names":[],"sources":["../../src/context/validator.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { ContextSnapshot, ValidateResult } from '../types.js'\n\nexport function validate(\n snapshot: ContextSnapshot | null,\n currentPlanCount: number\n): ValidateResult {\n if (snapshot === null) {\n return { valid: true, errors: [], context: null }\n }\n\n const errors: string[] = []\n\n if (currentPlanCount > 1) {\n errors.push(`存在 ${currentPlanCount} 个当前计划,应最多 1 个。`)\n }\n\n if (snapshot.currentPlan) {\n const planMd = join(snapshot.currentPlan.dir, 'plan.md')\n if (!existsSync(planMd)) {\n errors.push(`当前计划 plan-${snapshot.currentPlan.number} 缺少 plan.md。`)\n }\n\n if (snapshot.currentPlan.status === '未知') {\n errors.push(`当前计划 plan-${snapshot.currentPlan.number} 的状态格式严重不符合要求,请严格按照 \"> 状态: 已执行\" 或 \"> 状态: 未执行\" 的格式书写,禁止添加 emoji 或其他额外字符。`)\n }\n }\n\n for (const p of snapshot.preparing) {\n if (p.status === '未知') {\n errors.push(`待执行计划 plan-${p.number} 的状态格式严重不符合要求,请严格按照 \"> 状态: 已执行\" 或 \"> 状态: 未执行\" 的格式书写。`)\n }\n }\n\n const allNumbers: number[] = []\n for (const d of snapshot.done) allNumbers.push(d.number)\n if (snapshot.currentPlan) allNumbers.push(snapshot.currentPlan.number)\n for (const p of snapshot.preparing) allNumbers.push(p.number)\n\n const seen = new Set<number>()\n const duplicates = new Set<number>()\n for (const n of allNumbers) {\n if (seen.has(n)) duplicates.add(n)\n seen.add(n)\n }\n\n if (duplicates.size > 0) {\n const nums = [...duplicates].sort((a, b) => a - b).join(', ')\n errors.push(`计划编号冲突: ${nums}。`)\n }\n\n allNumbers.sort((a, b) => a - b)\n for (let i = 0; i < allNumbers.length; i++) {\n if (allNumbers[i] !== i + 1) {\n errors.push(`计划序列不连续或未从 1 开始。预期出现编号 ${i + 1},实际遇到编号 ${allNumbers[i]} (要求必须是从 1 开始顺序查询)。`)\n break\n }\n }\n\n return { valid: errors.length === 0, errors, context: snapshot }\n}\n"],"mappings":"sEAKA,SAAgB,EACd,EACA,EACgB,CAChB,GAAI,IAAa,KACf,MAAO,CAAE,MAAO,GAAM,OAAQ,EAAE,CAAE,QAAS,KAAM,CAGnD,IAAM,EAAmB,EAAE,CAEvB,EAAmB,GACrB,EAAO,KAAK,MAAM,EAAiB,iBAAiB,CAGlD,EAAS,cAEN,EADU,EAAK,EAAS,YAAY,IAAK,UAAU,CACjC,EACrB,EAAO,KAAK,aAAa,EAAS,YAAY,OAAO,cAAc,CAGjE,EAAS,YAAY,SAAW,MAClC,EAAO,KAAK,aAAa,EAAS,YAAY,OAAO,yEAAyE,EAIlI,IAAK,IAAM,KAAK,EAAS,UACnB,EAAE,SAAW,MACf,EAAO,KAAK,cAAc,EAAE,OAAO,sDAAsD,CAI7F,IAAM,EAAuB,EAAE,CAC/B,IAAK,IAAM,KAAK,EAAS,KAAM,EAAW,KAAK,EAAE,OAAO,CACpD,EAAS,aAAa,EAAW,KAAK,EAAS,YAAY,OAAO,CACtE,IAAK,IAAM,KAAK,EAAS,UAAW,EAAW,KAAK,EAAE,OAAO,CAE7D,IAAM,EAAO,IAAI,IACX,EAAa,IAAI,IACvB,IAAK,IAAM,KAAK,EACV,EAAK,IAAI,EAAE,EAAE,EAAW,IAAI,EAAE,CAClC,EAAK,IAAI,EAAE,CAGb,GAAI,EAAW,KAAO,EAAG,CACvB,IAAM,EAAO,CAAC,GAAG,EAAW,CAAC,MAAM,EAAG,IAAM,EAAI,EAAE,CAAC,KAAK,KAAK,CAC7D,EAAO,KAAK,WAAW,EAAK,GAAG,CAGjC,EAAW,MAAM,EAAG,IAAM,EAAI,EAAE,CAChC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAW,OAAQ,IACrC,GAAI,EAAW,KAAO,EAAI,EAAG,CAC3B,EAAO,KAAK,0BAA0B,EAAI,EAAE,UAAU,EAAW,GAAG,qBAAqB,CACzF,MAIJ,MAAO,CAAE,MAAO,EAAO,SAAW,EAAG,SAAQ,QAAS,EAAU"}
|
package/dist/stats.html
CHANGED
|
@@ -4930,7 +4930,7 @@ var drawChart = (function (exports) {
|
|
|
4930
4930
|
</script>
|
|
4931
4931
|
<script>
|
|
4932
4932
|
/*<!--*/
|
|
4933
|
-
const data = {"version":2,"tree":{"name":"root","children":[{"name":"cli.d.ts","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/cli.d.ts","uid":"
|
|
4933
|
+
const data = {"version":2,"tree":{"name":"root","children":[{"name":"cli.d.ts","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/cli.d.ts","uid":"04e2242d-1"}]},{"name":"cli.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/cli.ts","uid":"04e2242d-3"}]},{"name":"commands/done.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/done.ts","uid":"04e2242d-5"}]},{"name":"commands/install.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/install.ts","uid":"04e2242d-7"}]},{"name":"commands/printer.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/printer.ts","uid":"04e2242d-9"}]},{"name":"commands/status.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/status.ts","uid":"04e2242d-11"}]},{"name":"commands/sync.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/sync.ts","uid":"04e2242d-13"}]},{"name":"commands/validate.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/commands/validate.ts","uid":"04e2242d-15"}]},{"name":"content/actions.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/content/actions.ts","uid":"04e2242d-17"}]},{"name":"content/index.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/content/index.ts","uid":"04e2242d-19"}]},{"name":"context/archiver.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/context/archiver.ts","uid":"04e2242d-21"}]},{"name":"context/reader.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/context/reader.ts","uid":"04e2242d-23"}]},{"name":"context/validator.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/context/validator.ts","uid":"04e2242d-25"}]},{"name":"runner.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/runner.ts","uid":"04e2242d-27"}]},{"name":"tools.js","children":[{"name":"home/whj/codes/cat-kit/packages/agent-context/src/tools.ts","uid":"04e2242d-29"}]}],"isRoot":true},"nodeParts":{"04e2242d-1":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-0"},"04e2242d-3":{"renderedLength":1518,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-2"},"04e2242d-5":{"renderedLength":1349,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-4"},"04e2242d-7":{"renderedLength":985,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-6"},"04e2242d-9":{"renderedLength":909,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-8"},"04e2242d-11":{"renderedLength":946,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-10"},"04e2242d-13":{"renderedLength":745,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-12"},"04e2242d-15":{"renderedLength":763,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-14"},"04e2242d-17":{"renderedLength":8872,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-16"},"04e2242d-19":{"renderedLength":3024,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-18"},"04e2242d-21":{"renderedLength":1012,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-20"},"04e2242d-23":{"renderedLength":2081,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-22"},"04e2242d-25":{"renderedLength":1905,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-24"},"04e2242d-27":{"renderedLength":2037,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-26"},"04e2242d-29":{"renderedLength":2174,"gzipLength":0,"brotliLength":0,"metaUid":"04e2242d-28"}},"nodeMetas":{"04e2242d-0":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/cli.d.ts","moduleParts":{"cli.d.ts":"04e2242d-1"},"imported":[],"importedBy":[],"isEntry":true},"04e2242d-2":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/cli.ts","moduleParts":{"cli.js":"04e2242d-3"},"imported":[{"uid":"04e2242d-30"},{"uid":"04e2242d-31"},{"uid":"04e2242d-4"},{"uid":"04e2242d-6"},{"uid":"04e2242d-10"},{"uid":"04e2242d-12"},{"uid":"04e2242d-14"}],"importedBy":[],"isEntry":true},"04e2242d-4":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/done.ts","moduleParts":{"commands/done.js":"04e2242d-5"},"imported":[{"uid":"04e2242d-32"},{"uid":"04e2242d-33"},{"uid":"04e2242d-34"}],"importedBy":[{"uid":"04e2242d-2"}]},"04e2242d-6":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/install.ts","moduleParts":{"commands/install.js":"04e2242d-7"},"imported":[{"uid":"04e2242d-33"},{"uid":"04e2242d-26"},{"uid":"04e2242d-28"},{"uid":"04e2242d-8"}],"importedBy":[{"uid":"04e2242d-2"}]},"04e2242d-8":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/printer.ts","moduleParts":{"commands/printer.js":"04e2242d-9"},"imported":[{"uid":"04e2242d-32"}],"importedBy":[{"uid":"04e2242d-6"},{"uid":"04e2242d-12"}]},"04e2242d-10":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/status.ts","moduleParts":{"commands/status.js":"04e2242d-11"},"imported":[{"uid":"04e2242d-34"}],"importedBy":[{"uid":"04e2242d-2"}]},"04e2242d-12":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/sync.ts","moduleParts":{"commands/sync.js":"04e2242d-13"},"imported":[{"uid":"04e2242d-28"},{"uid":"04e2242d-26"},{"uid":"04e2242d-8"}],"importedBy":[{"uid":"04e2242d-2"}]},"04e2242d-14":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/commands/validate.ts","moduleParts":{"commands/validate.js":"04e2242d-15"},"imported":[{"uid":"04e2242d-34"}],"importedBy":[{"uid":"04e2242d-2"}]},"04e2242d-16":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/content/actions.ts","moduleParts":{"content/actions.js":"04e2242d-17"},"imported":[],"importedBy":[{"uid":"04e2242d-18"}]},"04e2242d-18":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/content/index.ts","moduleParts":{"content/index.js":"04e2242d-19"},"imported":[{"uid":"04e2242d-16"}],"importedBy":[{"uid":"04e2242d-26"}]},"04e2242d-20":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/archiver.ts","moduleParts":{"context/archiver.js":"04e2242d-21"},"imported":[{"uid":"04e2242d-35"},{"uid":"04e2242d-32"}],"importedBy":[{"uid":"04e2242d-34"}]},"04e2242d-22":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/reader.ts","moduleParts":{"context/reader.js":"04e2242d-23"},"imported":[{"uid":"04e2242d-35"},{"uid":"04e2242d-30"},{"uid":"04e2242d-32"}],"importedBy":[{"uid":"04e2242d-34"}]},"04e2242d-24":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/validator.ts","moduleParts":{"context/validator.js":"04e2242d-25"},"imported":[{"uid":"04e2242d-30"},{"uid":"04e2242d-32"}],"importedBy":[{"uid":"04e2242d-34"}]},"04e2242d-26":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/runner.ts","moduleParts":{"runner.js":"04e2242d-27"},"imported":[{"uid":"04e2242d-32"},{"uid":"04e2242d-30"},{"uid":"04e2242d-35"},{"uid":"04e2242d-28"},{"uid":"04e2242d-18"}],"importedBy":[{"uid":"04e2242d-6"},{"uid":"04e2242d-12"}]},"04e2242d-28":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/tools.ts","moduleParts":{"tools.js":"04e2242d-29"},"imported":[{"uid":"04e2242d-30"},{"uid":"04e2242d-32"}],"importedBy":[{"uid":"04e2242d-6"},{"uid":"04e2242d-12"},{"uid":"04e2242d-26"}]},"04e2242d-30":{"id":"node:fs","moduleParts":{},"imported":[],"importedBy":[{"uid":"04e2242d-2"},{"uid":"04e2242d-26"},{"uid":"04e2242d-28"},{"uid":"04e2242d-22"},{"uid":"04e2242d-24"}]},"04e2242d-31":{"id":"commander","moduleParts":{},"imported":[],"importedBy":[{"uid":"04e2242d-2"}]},"04e2242d-32":{"id":"node:path","moduleParts":{},"imported":[],"importedBy":[{"uid":"04e2242d-4"},{"uid":"04e2242d-26"},{"uid":"04e2242d-28"},{"uid":"04e2242d-8"},{"uid":"04e2242d-22"},{"uid":"04e2242d-24"},{"uid":"04e2242d-20"}]},"04e2242d-33":{"id":"@inquirer/prompts","moduleParts":{},"imported":[],"importedBy":[{"uid":"04e2242d-4"},{"uid":"04e2242d-6"}]},"04e2242d-34":{"id":"/home/whj/codes/cat-kit/packages/agent-context/src/context/index.ts","moduleParts":{},"imported":[{"uid":"04e2242d-22"},{"uid":"04e2242d-24"},{"uid":"04e2242d-20"}],"importedBy":[{"uid":"04e2242d-4"},{"uid":"04e2242d-10"},{"uid":"04e2242d-14"}]},"04e2242d-35":{"id":"node:fs/promises","moduleParts":{},"imported":[],"importedBy":[{"uid":"04e2242d-26"},{"uid":"04e2242d-22"},{"uid":"04e2242d-20"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":false,"brotli":false,"sourcemap":false}};
|
|
4934
4934
|
|
|
4935
4935
|
const run = () => {
|
|
4936
4936
|
const width = window.innerWidth;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-kit/agent-context",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "代理上下文管理工具",
|
|
5
5
|
"bin": {
|
|
6
6
|
"agent-context": "./dist/cli.js"
|
|
@@ -21,6 +21,6 @@
|
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@cat-kit/tsconfig": "1.0.0",
|
|
24
|
-
"@types/node": "^24.
|
|
24
|
+
"@types/node": "^24.12.0"
|
|
25
25
|
}
|
|
26
26
|
}
|
package/src/commands/status.ts
CHANGED
|
@@ -22,14 +22,12 @@ export async function statusCommand(): Promise<void> {
|
|
|
22
22
|
? `plan-${ctx.currentPlan.number} (${ctx.currentPlan.status})`
|
|
23
23
|
: '无'
|
|
24
24
|
const preparing =
|
|
25
|
-
ctx.preparing.length > 0
|
|
26
|
-
? ctx.preparing.map((p) => `plan-${p.number}`).join(', ')
|
|
27
|
-
: '无'
|
|
25
|
+
ctx.preparing.length > 0 ? ctx.preparing.map((p) => `plan-${p.number}`).join(', ') : '无'
|
|
28
26
|
|
|
29
|
-
console.log('')
|
|
30
|
-
console.log('Agent Context Status')
|
|
31
|
-
console.log('────────────────────')
|
|
32
|
-
console.log(`当前计划: ${current}`)
|
|
33
|
-
console.log(`待执行队列: ${preparing}`)
|
|
34
|
-
console.log(`已归档: ${ctx.
|
|
27
|
+
console.log('')
|
|
28
|
+
console.log('Agent Context Status')
|
|
29
|
+
console.log('────────────────────')
|
|
30
|
+
console.log(`当前计划: ${current}`)
|
|
31
|
+
console.log(`待执行队列: ${preparing}`)
|
|
32
|
+
console.log(`已归档: ${ctx.done.length} 个`)
|
|
35
33
|
}
|
package/src/commands/validate.ts
CHANGED
|
@@ -5,24 +5,24 @@ export async function validateCommand(): Promise<void> {
|
|
|
5
5
|
const result = validate(snapshot, currentPlanCount)
|
|
6
6
|
|
|
7
7
|
if (result.context === null) {
|
|
8
|
-
console.log('
|
|
8
|
+
console.log('⚠️ 无 .agent-context 目录')
|
|
9
9
|
return
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
if (result.valid) {
|
|
13
|
-
console.log('✅ 校验通过')
|
|
13
|
+
console.log('✅ 校验通过')
|
|
14
14
|
const ctx = result.context
|
|
15
15
|
const current = ctx.currentPlan
|
|
16
16
|
? `plan-${ctx.currentPlan.number} (${ctx.currentPlan.status})`
|
|
17
17
|
: '无'
|
|
18
|
-
console.log(` 当前计划: ${current}`)
|
|
19
|
-
console.log(` 待执行: ${ctx.preparing.length} 个`)
|
|
20
|
-
console.log(` 已归档: ${ctx.
|
|
18
|
+
console.log(` 当前计划: ${current}`)
|
|
19
|
+
console.log(` 待执行: ${ctx.preparing.length} 个`)
|
|
20
|
+
console.log(` 已归档: ${ctx.done.length} 个`)
|
|
21
21
|
return
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
for (const error of result.errors) {
|
|
25
|
-
console.log(`❌ ${error}`)
|
|
25
|
+
console.log(`❌ ${error}`)
|
|
26
26
|
}
|
|
27
27
|
process.exitCode = 1
|
|
28
28
|
}
|
package/src/context/reader.ts
CHANGED
|
@@ -5,7 +5,9 @@ import { join } from 'node:path'
|
|
|
5
5
|
import type { ContextSnapshot, PlanInfo, PlanStatus } from '../types.js'
|
|
6
6
|
|
|
7
7
|
const PLAN_DIR_RE = /^plan-(\d+)$/
|
|
8
|
-
const
|
|
8
|
+
const DONE_DIR_RE = /^plan-(\d+)(?:-\d{8})?$/
|
|
9
|
+
const EXACT_STATUS_RE = /^>\s*状态:\s*(未执行|已执行)$/m
|
|
10
|
+
const LOOSE_STATUS_RE = /^>?[ \t]*状态[::].*$/m
|
|
9
11
|
|
|
10
12
|
// ── Public API ───────────────────────────────────────
|
|
11
13
|
|
|
@@ -25,13 +27,13 @@ export async function readRawContext(
|
|
|
25
27
|
|
|
26
28
|
const currentPlans = await readPlanDirs(root)
|
|
27
29
|
const preparing = await readPlanDirs(join(root, 'preparing'))
|
|
28
|
-
const
|
|
30
|
+
const done = await readDonePlans(join(root, 'done'))
|
|
29
31
|
|
|
30
32
|
const snapshot: ContextSnapshot = {
|
|
31
33
|
root,
|
|
32
34
|
currentPlan: currentPlans[0] ?? null,
|
|
33
35
|
preparing,
|
|
34
|
-
|
|
36
|
+
done
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
return { snapshot, currentPlanCount: currentPlans.length }
|
|
@@ -45,8 +47,17 @@ export async function readPlanStatus(planDir: string): Promise<PlanStatus> {
|
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
const content = await readFile(planFile, 'utf-8')
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
|
|
51
|
+
const exactMatch = content.match(EXACT_STATUS_RE)
|
|
52
|
+
if (exactMatch) {
|
|
53
|
+
return exactMatch[1] as PlanStatus
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (LOOSE_STATUS_RE.test(content)) {
|
|
57
|
+
return '未知'
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return '未执行'
|
|
50
61
|
}
|
|
51
62
|
|
|
52
63
|
// ── Helpers ──────────────────────────────────────────
|
|
@@ -70,8 +81,20 @@ async function readPlanDirs(parentDir: string): Promise<PlanInfo[]> {
|
|
|
70
81
|
return plans.sort((a, b) => a.number - b.number)
|
|
71
82
|
}
|
|
72
83
|
|
|
73
|
-
async function
|
|
74
|
-
if (!existsSync(
|
|
75
|
-
const entries = await readdir(
|
|
76
|
-
|
|
84
|
+
async function readDonePlans(parentDir: string): Promise<Pick<PlanInfo, 'number' | 'dir'>[]> {
|
|
85
|
+
if (!existsSync(parentDir)) return []
|
|
86
|
+
const entries = await readdir(parentDir, { withFileTypes: true })
|
|
87
|
+
const plans: Pick<PlanInfo, 'number' | 'dir'>[] = []
|
|
88
|
+
|
|
89
|
+
for (const entry of entries) {
|
|
90
|
+
if (!entry.isDirectory()) continue
|
|
91
|
+
const match = entry.name.match(DONE_DIR_RE)
|
|
92
|
+
if (!match?.[1]) continue
|
|
93
|
+
plans.push({
|
|
94
|
+
number: parseInt(match[1], 10),
|
|
95
|
+
dir: join(parentDir, entry.name)
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return plans.sort((a, b) => a.number - b.number)
|
|
77
100
|
}
|
package/src/context/validator.ts
CHANGED
|
@@ -22,9 +22,20 @@ export function validate(
|
|
|
22
22
|
if (!existsSync(planMd)) {
|
|
23
23
|
errors.push(`当前计划 plan-${snapshot.currentPlan.number} 缺少 plan.md。`)
|
|
24
24
|
}
|
|
25
|
+
|
|
26
|
+
if (snapshot.currentPlan.status === '未知') {
|
|
27
|
+
errors.push(`当前计划 plan-${snapshot.currentPlan.number} 的状态格式严重不符合要求,请严格按照 "> 状态: 已执行" 或 "> 状态: 未执行" 的格式书写,禁止添加 emoji 或其他额外字符。`)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
for (const p of snapshot.preparing) {
|
|
32
|
+
if (p.status === '未知') {
|
|
33
|
+
errors.push(`待执行计划 plan-${p.number} 的状态格式严重不符合要求,请严格按照 "> 状态: 已执行" 或 "> 状态: 未执行" 的格式书写。`)
|
|
34
|
+
}
|
|
25
35
|
}
|
|
26
36
|
|
|
27
37
|
const allNumbers: number[] = []
|
|
38
|
+
for (const d of snapshot.done) allNumbers.push(d.number)
|
|
28
39
|
if (snapshot.currentPlan) allNumbers.push(snapshot.currentPlan.number)
|
|
29
40
|
for (const p of snapshot.preparing) allNumbers.push(p.number)
|
|
30
41
|
|
|
@@ -40,5 +51,13 @@ export function validate(
|
|
|
40
51
|
errors.push(`计划编号冲突: ${nums}。`)
|
|
41
52
|
}
|
|
42
53
|
|
|
54
|
+
allNumbers.sort((a, b) => a - b)
|
|
55
|
+
for (let i = 0; i < allNumbers.length; i++) {
|
|
56
|
+
if (allNumbers[i] !== i + 1) {
|
|
57
|
+
errors.push(`计划序列不连续或未从 1 开始。预期出现编号 ${i + 1},实际遇到编号 ${allNumbers[i]} (要求必须是从 1 开始顺序查询)。`)
|
|
58
|
+
break
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
43
62
|
return { valid: errors.length === 0, errors, context: snapshot }
|
|
44
63
|
}
|
package/src/types.ts
CHANGED
|
@@ -43,7 +43,7 @@ export interface RunResult extends ApplyMutationResult {
|
|
|
43
43
|
|
|
44
44
|
// ── Context types ────────────────────────────────────
|
|
45
45
|
|
|
46
|
-
export type PlanStatus = '未执行' | '已执行'
|
|
46
|
+
export type PlanStatus = '未执行' | '已执行' | '未知'
|
|
47
47
|
|
|
48
48
|
export interface PlanInfo {
|
|
49
49
|
number: number
|
|
@@ -55,7 +55,7 @@ export interface ContextSnapshot {
|
|
|
55
55
|
root: string
|
|
56
56
|
currentPlan: PlanInfo | null
|
|
57
57
|
preparing: PlanInfo[]
|
|
58
|
-
|
|
58
|
+
done: Pick<PlanInfo, 'number' | 'dir'>[]
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
export interface ValidateResult {
|