@critical-path/core
基础域引擎、域事件总线、图形周期检测和存储适配器 关键路径。 。 。 .
升级? 升级一次
@critical-path/*组合在一起。 编码代理: 遵循 更新(md); 已标记断开的更改 刹车 此软件包中CHANGELOG.md。 。 。 .
* 特性
- 一个引擎,一套规则数字 :
CriticalPathEngine执行每个不变量(工作流程状态和过渡,衍生字段,引用,权限)给直接呼叫者,HTTP API,客户端和MCP都一样. - 输入域事件总线: 内地酒吧/分店
DomainEventBus允许对颗粒域事件进行被动订阅(task.created, (中文(简体) ),task.status_changed, (中文(简体) ),time.logged, (中文(简体) ),dependency.added(见a/c.5/49/70,附件). - DAG 图形循环变量:已建成的地貌验证(
detectDependencyCycle, (中文(简体) ),CircularDependencyError确保严格的循环任务依赖图。 依赖是:blocking或者说relates_to(信息,从来不是时间表或周期检查的一部分);precedenceOf读取依赖的方向. - 自定义字段值对象验证: 严格型号检查( E)
validateCustomFieldValues, (中文(简体) ),CustomFieldValidationError对照配置的项目场计划. - 接口隔离仓库: 重点储存库合同(
ProjectRepository, (中文(简体) ),TaskRepository, (中文(简体) ),WorkflowRepository(a/cn.9/wg.iii/wp.ii等)StorageAdapter。 。 。 . - 插件寿命周期架构:可扩展的钩子(
beforeTaskCreate, (中文(简体) ),afterTaskUpdate, (中文(简体) ),beforeTaskDelete(见a/c.5/49/70,附件). - 多个内建存储适应器数字 :
InMemoryStore:用于本地 dev 和测试的快,零配置的内置存储.SQLiteStore: 由本地的Node.js SQLite(英语:node:sqlite) (中文(简体) ).FirebaseStore:Firestore收集绘图,用于云源网络和移动后端.
- 附件文件存储适配器数字 :
InMemoryFileStore: 轻量级内置二进制资产存储,并带有预先签名的URL模拟.S3StorageAdapter: S3 / MinIO / Cloudflare R2 适配器由您的 AWS SDK v3 客户端驱动,命令类和getSignedUrl前缀(核心本身没有AWS依赖性). 支持签名上传和私人-bucket签名下载.FirebaseStorageAdapter: Google Cloud存储 & Firebase 存储桶适配器.
- 线索对话、讨论和情感反应数字 :
- 密报答复
parentId),多作者分类学(user, (中文(简体) ),agent, (中文(简体) ),system),emoji反应addCommentReaction, (中文(简体) ),removeCommentReaction),以及实时域名事件流(comment.created, (中文(简体) ),comment.updated, (中文(简体) ),comment.deleted, (中文(简体) ),comment.reaction.added, (中文(简体) ),comment.reaction.removed) (中文(简体) ).
- 密报答复
- 多收件人支持和代理协作数字 :
- 头等舱
TaskAssignee分类学支持跨用户,自主的AI代理,以及角色元数据和自定义的Avatar URL的团队共同任务.
- 头等舱
- 双向工作流程过渡数字 :
- 对称的过渡助手( E)
getAllowedNextStatuses, (中文(简体) ),getAllowedPreviousStatuses)和通过定制工作流程状态向后移动任务的引擎方法.
- 对称的过渡助手( E)
- 通用语义状态和障碍状态框架数字 :
- 清洁的三级状态架构:通用语义状态(
not_started, (中文(简体) ),in_progress, (中文(简体) ),completed, (中文(简体) ),canceled),可自定义的工作流程定义状态category和自动系统衍生的隐含状态isReady, (中文(简体) ),isBlocked, (中文(简体) ),blockingTaskIds, (中文(简体) ),isOverdue, (中文(简体) ),isUpcoming, (中文(简体) ),isUnplanned, (中文(简体) ),isUnassigned, (中文(简体) ),isStalled, (中文(简体) ),isOverEstimate, (中文(简体) ),isPaceWarning) (中文(简体) ).
- 清洁的三级状态架构:通用语义状态(
- 交付品数字 :
- 产出一个项目,与产生这些项目的任务挂钩,并按语义分类绘制可配置状态集(
deliverableStatusDefinitions; 默认DEFAULT_DELIVERABLE_STATUSES),自动deliveredAt,以及outputUrls。 。 。 . - 创意制作的预设:
CREATIVE_DELIVERABLE_STATUSES编辑DEFAULT_CREATIVE_WORKFLOW任务工作流程. - 通过
getDeliverableSummary()实现进度百分比、完成的任务和分配任务估计/记录的总时数.
- 产出一个项目,与产生这些项目的任务挂钩,并按语义分类绘制可配置状态集(
- 抽象和关键路径方法模型(CPM)数字 :
- 多尺度时间轴合成:大型鸟类眼相滚动(
getTimelineLadder({ level: 'macro' })),标准甘特视图有地貌CPM前行/后行出行和全浮/下行,并有混凝土地平面(附件、可交付品、清单项目、日常努力直方图和现实三角洲). - 单个任务背景钻入
getTaskLadder(taskId)。 。 。 . - 综合CPM分析
calculateCriticalPath(projectId)确定项目瓶颈任务和关键路径持续时间.
- 多尺度时间轴合成:大型鸟类眼相滚动(
- 工作时间安排、工作时间、工作日和假日数字 :
- 可配置
WorkSchedule数据模型界定日间活动工作时间(如:9:00-17:00)、非工作日/周末、组织或区域Holiday豁免. - 多级别时间表继承等级:任务指定人/团队 - > 工程 - > 全球引擎默认( E)
DEFAULT_WORK_SCHEDULE按工作量和能力计算。 CPM日期预测使用项目(或引擎默认)时间表. - 日历数学域操作( C)
addWorkingHours, (中文(简体) ),subtractWorkingHours, (中文(简体) ),getWorkingHoursBetween, (中文(简体) ),getWorkingDaysBetween, (中文(简体) ),getNetAvailableCapacity) (中文(简体) ). - 在关键路径方法(CPM)前行和后后行时间表通行证期间自动排除周末和假日(
earlyStartDate, (中文(简体) ),earlyFinishDate, (中文(简体) ),lateStartDate, (中文(简体) ),lateFinishDate, (中文(简体) ),totalWorkingHours, (中文(简体) ),projectEndDate) (中文(简体) ). - 工作量分配和工作日时间表差异衡量尺度
scheduleVarianceWorkingDays) (中文(简体) ).
- 可配置
- 无头工作负荷和能力分布(Streamgraphs and Captain Project)数字 :
- 跨自定义间隔的时间序列汇总
day, (中文(简体) ),week, (中文(简体) ),month)和维度assignee, (中文(简体) ),team, (中文(简体) ),taskType, (中文(简体) ),priority, (中文(简体) ),status) (中文(简体) ). - 可累积努力分布衡量标准(
scheduled, (中文(简体) ),logged, (中文(简体) ),remaining, (中文(简体) ),blended),并配有相接而无间隙的日历桶和为D3准备的零填充的表格系列矩阵 (d3.stack().offset(d3.stackOffsetWiggle)) (中文(简体) ). - 每人和团队动态能力模型,报告桶级能力阈值和使用率(
totalHours / totalCapacity) (中文(简体) ).
- 跨自定义间隔的时间序列汇总
- Base-62 细小词典索引数字 :
- 零依赖性 基-62分数索引
generateKeyBetween, (中文(简体) ),generateNKeysBetween)用于即时Kanban和积压重排顺序而无需重新索引或数组转换.
- 零依赖性 基-62分数索引
- 代码- Immune 引用和标签提取数字 :
- 高性能说明
extractMentions自动加减码压制(stripMarkdownCode)在解析用户和代理手柄时忽略了代码块,内置代码,以及URL.
- 高性能说明
- 任务周期和语义状态数字 :
- 全套功能上游(
isDraftTask, (中文(简体) ),isArchivedTask, (中文(简体) ),isTrashedTask, (中文(简体) ),isTaskCompleted, (中文(简体) ),isTaskInProgress, (中文(简体) ),isTaskActive, (中文(简体) ),isTempTaskId用于无头UI渲染.
- 全套功能上游(
- 补全时间标记和进步数字 :
- 自动
actualEndDate财务报告和审定财务报表completedAt进入完成或取消状态时的寿命周期时间戳,在重开任务时自动时间戳清除和进度重设(100 - > 0).
- 自动
使用实例
1. 启动域事件的引擎并订阅
import { CriticalPathEngine, SQLiteStore, type TaskStatusChangedEvent } from '@critical-path/core';
const store = new SQLiteStore({ filename: 'critical-path.db' });
const engine = new CriticalPathEngine({ store });
// Subscribe to specific typed domain events
engine.events.subscribe<TaskStatusChangedEvent>('task.status_changed', (event) => {
console.log(`Task ${event.aggregateId} moved from ${event.payload.previousStatus} to ${event.payload.newStatus}`);
});
// Or subscribe to all domain events with wildcard
engine.events.subscribe('*', (event) => {
console.log(`[Domain Event] ${event.name}`, event);
});
store 必须是适配器实例( e)InMemoryStore (默认情况下). 关键路径不存储用户: 通过您的应用程序的用户目录为 users (一个阵列,或与代理用户一起调用的一个函数)因此工作量和能力计算使用真实姓名,每周容量和时间表:
const engine = new CriticalPathEngine({
store,
users: async (actor) => (await myAuth.listUsers(actor?.tenantId)).map(toCriticalPathUser)
});
2. 引擎中生存的变种者
import { CriticalPathEngine } from '@critical-path/core';
const engine = new CriticalPathEngine();
const project = await engine.createProject({ name: 'Payments' });
const task = await engine.createTask({ projectId: project.id, title: 'Implement Payment Gateway', priority: 'high' });
// Workflow transitions are enforced; semanticStatus and timestamps are derived
await engine.updateTask(task.id, { status: 'in_progress' });
// Hours come from time entries
await engine.logTime({ taskId: task.id, hours: 3.5, isBillable: true });
3. DAG 依赖性周期预防
import { CircularDependencyError } from '@critical-path/core';
try {
await engine.addDependency({
taskId: 'task_C',
dependsOnTaskId: 'task_A',
type: 'blocking'
});
} catch (error) {
if (error instanceof CircularDependencyError) {
console.error(`Blocked cyclic dependency! Cycle path: ${error.cyclePath.join(' -> ')}`);
}
}
删除依赖关系 engine.removeDependency(dependencyId) (出版物) dependency.removed) (中文(简体) ).
删除级联 : deleteTask 删除子任务( 或用 { subtasks: 'detach' }),依赖性,注释,所存储文件的附件和时间条目; deleteProject 还删除了集装箱、迭代和可交付品;删除了集装箱、迭代或可交付品,从而清除了有关其任务的参考资料。 活动记录作为审计线索保存。 与 transaction (例如: SQLiteStore),每个级联都是原子:如果任何步骤失败,例如因为一个级联是原子级: beforeTaskDelete 钩子扔给子任务,没有被删除. 事件,后呼和删除文件仅在执行后运行.
循环检测遵循整个上游链,因此间接循环(A → B → C → D → A)以及直接循环被否决.
请求有效载荷Schemas(@critical-path/core/schemas(中文(简体) )
import { CreateTaskSchema, UpdateTaskSchema, parsePayload } from '@critical-path/core/schemas';
const input = parsePayload(CreateTaskSchema, await request.json()); // throws ValidationError with `issues`
await engine.createTask(input);
创建并更新用于工作流程,项目,任务,依赖,可交付,团队,容器,迭代,评论,反应,附件和时间条目的计划. 它们严格:拒绝服务器指定字段,身份字段和未知密钥. 计划就住在一条子道上 如此地导入 @critical-path/core 在浏览器捆绑中不会拉入zod. 如果域类型获得其计划所缺少的字段,则编译时间测试失败.
自定义存储适配器( C)
执行 StorageAdapter 用于您的数据库,并用内置适配器通过的同一套件校验:
import { describe, it, expect } from 'vitest';
import { runStorageAdapterConformance } from '@critical-path/core/testing';
runStorageAdapterConformance({ name: 'PostgresStore', createStore: () => new PostgresStore(db), describe, it, expect });
上传限制
new CriticalPathEngine({
fileStorage,
uploads: { maxBytes: 25 * 1024 * 1024, allowedMimeTypes: ['image/*', 'application/pdf'] }
});
限制适用于直接上传(对照已解码的大小)、预先签名上传(内容类型)和已注册附件(已宣布) sizeBytes 财务报告和审定财务报表 mimeType) (中文(简体) ). 预先指定的上传直接到存储处,所以在您的桶策略中也封住它们的大小.
查询和放置
const page = await engine.queryTasks({ projectId, status: ['todo', 'in_progress'], assigneeId: 'ana', limit: 50 });
const next = await engine.queryTasks({ projectId, limit: 50, cursor: page.nextCursor });
const feed = await engine.queryActivities({ projectId, limit: 20 }); // newest first
const thread = await engine.queryComments({ taskId, limit: 50 }); // oldest first
任务和评论页最旧,活动最新,使用密钥集光标(createdAt,则 id) (中文(简体) ). SQLiteStore 带有索引的 SQL 过滤器和页面. FirebaseStore 将工程过滤器推倒,并在内存中应用其余部分. 无 projectId,结果仅限于演员能够读取的项目.
授权和多期限
import { CriticalPathEngine, createRolePolicy } from '@critical-path/core';
const engine = new CriticalPathEngine({ store, authorize: createRolePolicy() });
const asVic = engine.withActor({ userId: 'vic', tenantId: 'acme' });
await asVic.createTask({ projectId, title: 'x' }); // ForbiddenError if vic is only a viewer
检查运行 withActor 视图(基准引擎可信)。 角色来自 project.members: 用户({ userId, role })或整个团队({ teamId, role }),其中包含角色 viewer < contributor < project_manager < admin项目创建者成为 admin。演员 roles: ['admin'] 超级用户。 演员不能阅读或属于另一个租户的项目,其行为如同不存在一样(NotFoundError) (中文(简体) ). 名单经过过滤。 通过视图创建的唱片由演员所盖章 tenantId。关于完整的许可矩阵和自定义政策,请参见文件网站的授权页.
自定义字段
每个实体(项目、工作流程、团队、任务、容器、迭代、交付品、评论、附件、时间条目、依赖性、网络呼喊)都接受一个 customFields JSON 对象在创建和更新您自己的数据上。 任务自定义字段被验证为项目 customFieldDefinitions;在其他实体中,任何JSON对象都按原样存储。 更新替换整个对象.
网络呼号
const { webhook, secret } = await engine.createWebhook({
name: 'CI',
url: 'https://ci.example.com/hooks',
events: ['task.created', 'task.status_changed'] // or ['*']
});
// Receivers: verifyWebhookSignature({ secret, body, timestamp, signature })
每个域事件都可以交付. 运送 X-CriticalPath-Signature (HMAC-SHA256 完毕) "<timestamp>.<body>"),10s后超时,并重试以指数回放(webhookDelivery 选项)。 默认队列是进程 。 为了持久运送,通过 new OutboxWebhookQueue(store) 作为 webhookDelivery.queue 打电话 outbox.start() (或 processDue() 工作需要时, 打开 SQLiteStore,任务与产生这些任务的突变在同一交易中写出。 您也可以带自己的队列打电话 engine.webhooks.deliver(job). 在每次尝试之前,拒绝将目标确定为私人地址,不遵循重定向。 秘诀只有在创作时才归还.
将突变归咎于用户(withActor(中文(简体) )
const asAlice = engine.withActor({ userId: 'alice', username: 'Alice' });
await asAlice.updateTask(taskId, { status: 'in_progress' }); // activity actorId: 'alice'
await asAlice.addComment({ taskId, content: 'On it' }); // authorId: 'alice'
withActor 返回每个请求视图,该视图与基引擎共享商店、插件和事件总线。 在视图中,每个写入都归于演员:活动日志条目,评论作者,反应,时间条目,附件上传器,以及默认任务 reporterId。 。 。 . updateTask 从未从更新的有效载荷读取身份; 信任的服务器侧自动化可以通过 updateTask(id, updates, { actorId }) 当然 没有风景, addComment反应和 createAttachment 接受选项 authorId 编号 : userId 编号 : uploaderId 并回到 'system'。 。 。 . @critical-path/server 通过视图(解析后的用户,或 anonymous) (中文(简体) ).
其他域错误导出给调用者和路由处理器以映射 : ValidationError (输入不良,例如非阳性记录时数)和 NotFoundError (缺少参考实体). engine.deleteProject(id) 删除工程及其任务 deleteTask,然后出版 project.deleted。 。 。 .
4. 跟踪创意交付和滚动计量
import { CriticalPathEngine, CREATIVE_DELIVERABLE_STATUSES } from '@critical-path/core';
const engine = new CriticalPathEngine();
// Creative statuses for this project's deliverables (the default set is planned / in_progress / in_review / delivered / canceled)
await engine.updateProject('proj_1', { deliverableStatusDefinitions: CREATIVE_DELIVERABLE_STATUSES });
// 1. Create deliverable; domain-specific details go in customFields
const deliverable = await engine.createDeliverable({
projectId: 'proj_1',
title: 'Brand Hero Video 30s',
customFields: { format: 'ProRes 422HQ', resolution: '3840x2160', fps: 24 }
});
// 2. Attach tasks to deliverable
const storyboard = await engine.createTask({
projectId: 'proj_1',
deliverableId: deliverable.id,
title: 'Storyboard & Animatic',
status: 'approved',
estimatedHours: 12,
progress: 100
});
// Logged hours come from time entries
await engine.logTime({ taskId: storyboard.id, hours: 12 });
// 3. Rollup metrics
const summary = await engine.getDeliverableSummary(deliverable.id);
console.log(`Progress: ${summary?.progressPercentage}%, Total tasks: ${summary?.totalTasks}`);
5. 评价不良状况和依赖性准备情况
// Evaluates task status category, upstream dependency states, schedules, assignees, and pace
const state = await engine.getTaskLifecycleState('task_123');
if (state?.isBlocked) {
console.warn(`Task blocked by upstream tasks: ${state.blockingTaskIds.join(', ')}`);
} else if (state?.isReady) {
console.log('All dependencies satisfied! Task is ready to start.');
}
if (state?.isOverEstimate) {
console.warn('Task logged hours have exceeded estimated hours!');
}
if (state?.isPaceWarning) {
console.warn('Task has been active longer than its estimated duration!');
}
6. 任务计量、推算实际和EVM
// Calculate comprehensive task metrics
const metrics = await engine.getTaskMetrics('task_123');
console.log('Inferred Actuals:', metrics?.inferredActuals);
// { actualStartDate: '...', isStartDateInferred: false, activeWorkingHours: 18.5 }
console.log('Progress Inference:', metrics?.progress);
// { progressPercentage: 80, source: 'todos', breakdown: { todoProgress: 80 } }
console.log('Earned Value Management:', metrics?.evm);
// { plannedValue: 20, earnedValue: 16, actualCost: 18, cpi: 0.89, spi: 0.8 }
// Reconstruct historical progress time-series and curve profile
const history = await engine.getTaskProgressHistory('task_123');
console.log('Curve Profile:', history?.curveProfile);
// 's_curve' | 'linear' | 'early_surge' | 'late_rush' | 'stalled'
7. 无头工作量和能力分布(图)
// Calculate weekly capacity and workload distribution across assignees
const workload = await engine.getWorkloadDistribution('proj_123', {
interval: 'week',
groupBy: 'assignee',
metric: 'blended'
});
console.log('Series Keys (Assignee IDs):', workload.seriesKeys);
console.log('Contiguous Weekly Buckets:', workload.buckets);
// Each bucket contains zero-filled numeric values for all seriesKeys:
// {
// date: '2026-09-01',
// timestamp: 1788220800000,
// values: { alice: 32, bob: 18, unassigned: 0 },
// capacity: { alice: 40, bob: 40 },
// totalHours: 50,
// totalCapacity: 80,
// utilizationRatio: 0.625
// }
8. 工作时间安排、工作时间和假日
import { CriticalPathEngine, type WorkSchedule, addWorkingHours } from '@critical-path/core';
// Define a project schedule with 4-day workweeks and holidays
const engineeringSchedule: WorkSchedule = {
timezone: 'UTC',
days: [
{ dayOfWeek: 0, isWorkingDay: false }, // Sunday
{ dayOfWeek: 1, isWorkingDay: true, hours: [{ start: '09:00', end: '17:00' }] }, // Monday
{ dayOfWeek: 2, isWorkingDay: true, hours: [{ start: '09:00', end: '17:00' }] }, // Tuesday
{ dayOfWeek: 3, isWorkingDay: true, hours: [{ start: '09:00', end: '17:00' }] }, // Wednesday
{ dayOfWeek: 4, isWorkingDay: true, hours: [{ start: '09:00', end: '17:00' }] }, // Thursday
{ dayOfWeek: 5, isWorkingDay: false }, // Friday
{ dayOfWeek: 6, isWorkingDay: false } // Saturday
],
holidays: [
{ date: '2026-12-25', name: 'Christmas Day' },
{ date: '2026-12-26', name: 'Boxing Day' }
]
};
const engine = new CriticalPathEngine({
defaultSchedule: engineeringSchedule
});
// CPM automatically rolls over non-working days and holidays
const cpm = await engine.calculateCriticalPath('proj_123', {
projectStartDate: '2026-09-01T09:00:00Z',
schedule: engineeringSchedule
});
console.log('Project End Date (skipping weekends & holidays):', cpm.projectEndDate);
console.log('Total Working Hours on Critical Path:', cpm.totalWorkingHours);
// Schedule each task on its assignee's (or team's) calendar instead, using the `users` directory
const byAssignee = await engine.calculateCriticalPath('proj_123', { calendars: 'assignee' });
// ...and limit each assignee to one task at a time (resource levelling)
const leveled = await engine.calculateCriticalPath('proj_123', { calendars: 'assignee', levelResources: true });
console.log(leveled.unleveledProjectEndDate, '->', leveled.projectEndDate);
与 calendars: 'assignee' (或 criticalPathCalendars: 'assignee' 每个任务使用其受让人的时间表,然后使用其团队的时间表,然后使用项目日历。 在日期上运行的传出,在每项任务的日历中测量松懈度,每个日历都按自身来评价 timezone (IANA名称;默认为UTC),包括防日变化. levelResources: true 额外拖延任务,所以没有人同时工作(优先规则) levelingPriority报告) levelingDelayHours 财务报告和审定财务报表 waitingOn 每个任务。 任务与 allocation 低于1级者承担其受让人的这一份额(工作时为16小时,工作时长为0.5个,工作时长为32个小时);在每人100%范围内予以平整;以及 overallocations 列出超过100%的预定时间。 团队作为 headcount 人员(默认:成员计数)由团队任务和成员自身任务共享. 完成任务不需要时间. calculatePortfolioCriticalPath({ projectIds }) 共同开展若干项目,共享人员和团队; includeHiddenWork 还计算了不可读项目的工作,作为 'hidden'。 。 。 . effort: 'remaining' 仅列出在进行中的任务中剩下的内容.
保存计划 engine.createBaseline(projectId, { name }) 通过 baselineId 以后进行分析,以了解每项任务和项目结束的进展情况。 带有分任务的任务为总结任务,报告为叶子卷起(isSummary每个叶子都具有依赖性和期限。 未估计的任务使用 defaultEstimateHours (默认 1) 并列于 unestimatedTaskIds任务 isMilestone: true 零期限检查站(其估计数被忽略)。 A 类 deadline 任何任务都封顶了它的后期完成:没有完成的预测显示,在驱动它的道路上出现负松动 deadlineDate 财务报告和审定财务报表 deadlineVarianceHours 每个任务和 missedDeadlineTaskIds 关于分析。 仅限日期的截止日期是指该工作日的结束. earliestStart (不早于)和依赖性 lagHours (等前作;负取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取 项目日历模式需要一个起始日期来应用这些日期限制.
9. 小数语法索引编制(Kanban重排)
import { generateKeyBetween, generateNKeysBetween } from '@critical-path/core';
// Insert an item between two adjacent items without shifting arrays:
const firstItemOrder = 'a0';
const secondItemOrder = 'a1';
const newItemOrder = generateKeyBetween(firstItemOrder, secondItemOrder);
// -> 'a0V' (lexicographically between 'a0' and 'a1')
// Generate keys for multiple items inserted at once:
const newKeys = generateNKeysBetween(firstItemOrder, secondItemOrder, 3);
10. 《守则》和《参考提取法》
import { extractMentions } from '@critical-path/core';
const markdown = `
Check with @alice and agent @gemini-bot.
Ignore \`@not_a_user\` in inline code and code blocks:
\`\`\`ts
const query = "@ignored";
\`\`\`
`;
const mentions = extractMentions(markdown);
// -> ['alice', 'gemini-bot']
QQ 创建自定义插件
import type { CriticalPathPlugin } from '@critical-path/core';
export const auditPlugin: CriticalPathPlugin = {
id: 'audit-logger',
name: 'Audit Logger',
version: '1.0.0',
hooks: {
beforeTaskCreate: (task) => {
return { ...task, tags: [...(task.tags || []), 'AUDITED'] };
}
}
};
插件也可以贡献 init(engine) (等待通过) engine.ready, (中文(简体) ), customFieldTypes (项目的有效自定义字段类型) customFieldDefinitions)和HTTP 软件 routes 编号 : middleware 服务于 @critical-path/server (路线出现于 /openapi.json,用其可选 openapi 页:1 执行前输出像调用器输入一样被验证,执行后错误会被记录下来而不是失败写入.