@dawipong/opcflow 0.7.0 → 0.8.0

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.
Files changed (2) hide show
  1. package/dist/cli.mjs +141 -76
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -837,6 +837,71 @@ var init_kind = __esm({
837
837
  }
838
838
  });
839
839
 
840
+ // core/roles.ts
841
+ function getRoleRegistry(config) {
842
+ const merged = {};
843
+ for (const [role, spec] of Object.entries(DEFAULT_ROLE_REGISTRY)) merged[role] = { ...spec };
844
+ for (const [role, kinds] of Object.entries(config.roleProduces ?? {})) {
845
+ merged[role] = { ...merged[role] ?? { produces: [] }, produces: kinds };
846
+ }
847
+ for (const [role, override] of Object.entries(config.roles ?? {})) {
848
+ merged[role] = { ...merged[role] ?? { produces: [] }, ...override };
849
+ }
850
+ return merged;
851
+ }
852
+ function ownerRoleOf(config, kind) {
853
+ for (const [role, spec] of Object.entries(getRoleRegistry(config))) {
854
+ if (spec.produces.includes(kind)) return role;
855
+ }
856
+ if (kind === "code") return "developer";
857
+ return null;
858
+ }
859
+ var DEFAULT_ROLE_REGISTRY;
860
+ var init_roles = __esm({
861
+ "core/roles.ts"() {
862
+ "use strict";
863
+ init_kind();
864
+ DEFAULT_ROLE_REGISTRY = {
865
+ "product-manager": {
866
+ produces: ["project", "roles", "glossary", "flow", "module-prd", "page-prd"]
867
+ },
868
+ architect: {
869
+ produces: ["db-doc", "api-doc"],
870
+ requires: [{ desc: "PM \u4EA7\u51FA(\u6A21\u5757/\u9875\u9762 PRD)", kinds: PM_KINDS }],
871
+ dispatch: [
872
+ { at: "module", endpoint: "common", content: "\u8BBE\u8BA1 {module} \u6A21\u5757\u6570\u636E\u5E93" },
873
+ { at: "module", endpoint: "service", content: "\u8BBE\u8BA1 {module} \u6A21\u5757 API \u6587\u6863" }
874
+ ]
875
+ },
876
+ designer: {
877
+ produces: ["design-system", "design-prompt", "prototype"],
878
+ requires: [{ desc: "PM \u4EA7\u51FA(\u6A21\u5757/\u9875\u9762 PRD)", kinds: PM_KINDS }],
879
+ dispatch: [
880
+ { at: "endpoint", ifMissingKind: "design-system", produces: ["design-system"], content: "\u5EFA\u7ACB {endpoint} \u7AEF\u8BBE\u8BA1\u7CFB\u7EDF(\u8BE5\u7AEF\u9996\u4E2A\u9875\u9762\u8BBE\u8BA1\u524D\u7F6E)" },
881
+ { at: "page", produces: ["design-prompt", "prototype"], content: "\u8BBE\u8BA1 {endpoint}/{page} \u9875\u9762(\u63D0\u793A\u8BCD+\u539F\u578B)" }
882
+ ]
883
+ },
884
+ developer: {
885
+ produces: ["code"],
886
+ requires: [
887
+ { desc: "\u6570\u636E\u5E93\u6587\u6863", kinds: ["db-doc"] },
888
+ { desc: "API \u6587\u6863", kinds: ["api-doc"], when: { endpointNot: "service" } },
889
+ { desc: "designer {endpoint} \u8BBE\u8BA1\u7A3F", kinds: ["design-prompt", "prototype"], when: { endpointNot: "service" } }
890
+ ],
891
+ dispatch: [
892
+ { at: "module", endpoint: "service", content: "\u5B9E\u73B0 {module} \u6A21\u5757 service \u7AEF" },
893
+ { at: "page", content: "\u5B9E\u73B0 {endpoint}/{page} \u9875\u9762" }
894
+ ],
895
+ onQaFail: "rework"
896
+ },
897
+ qa: {
898
+ produces: ["acceptance"],
899
+ dispatch: [{ at: "page", type: "qa", content: "\u9A8C\u6536 {endpoint}/{page} \u9875\u9762" }]
900
+ }
901
+ };
902
+ }
903
+ });
904
+
840
905
  // core/derive.ts
841
906
  var derive_exports = {};
842
907
  __export(derive_exports, {
@@ -974,31 +1039,22 @@ function levelFilter(level, task) {
974
1039
  }
975
1040
  }
976
1041
  function producedKinds(ctx, task) {
977
- const declared = ctx.config.roleProduces[task.role] ?? [];
978
- if (task.role === "designer") {
979
- return task.page ? declared.filter((k) => k !== "design-system") : ["design-system"];
980
- }
981
- return declared;
982
- }
983
- function existRequirements(task) {
984
- const m = task.module;
985
- switch (task.role) {
986
- case "architect":
987
- case "designer":
988
- return [{ desc: "PM \u4EA7\u51FA(\u6A21\u5757/\u9875\u9762 PRD)", level: "exist", kinds: PM_KINDS, filter: { module: m } }];
989
- case "developer": {
990
- if (task.endpoint === "service") {
991
- return [{ desc: "\u6570\u636E\u5E93\u6587\u6863", level: "exist", kinds: ["db-doc"], filter: { module: m } }];
992
- }
993
- return [
994
- { desc: "\u6570\u636E\u5E93\u6587\u6863", level: "exist", kinds: ["db-doc"], filter: { module: m } },
995
- { desc: "API \u6587\u6863", level: "exist", kinds: ["api-doc"], filter: { module: m } },
996
- { desc: `designer ${task.endpoint} \u8BBE\u8BA1\u7A3F`, level: "exist", kinds: ["design-prompt", "prototype"], filter: { module: m, endpoint: task.endpoint } }
997
- ];
998
- }
999
- default:
1000
- return [];
1042
+ const spec = getRoleRegistry(ctx.config)[task.role];
1043
+ if (!spec) return [];
1044
+ const wantPage = !!task.page;
1045
+ const rule = (spec.dispatch ?? []).find((d) => (wantPage ? d.at === "page" : d.at !== "page") && d.produces);
1046
+ return rule?.produces ?? spec.produces;
1047
+ }
1048
+ function existRequirements(ctx, task) {
1049
+ const spec = getRoleRegistry(ctx.config)[task.role];
1050
+ const reqs = [];
1051
+ for (const r of spec?.requires ?? []) {
1052
+ if (r.when?.endpoint && task.endpoint !== r.when.endpoint) continue;
1053
+ if (r.when?.endpointNot && task.endpoint === r.when.endpointNot) continue;
1054
+ const filter = r.kinds.includes("design-prompt") || r.kinds.includes("prototype") ? { module: task.module, endpoint: task.endpoint } : { module: task.module };
1055
+ reqs.push({ desc: r.desc.replaceAll("{endpoint}", task.endpoint ?? ""), level: "exist", kinds: r.kinds, filter });
1001
1056
  }
1057
+ return reqs;
1002
1058
  }
1003
1059
  function approvedRequirements(ctx, task) {
1004
1060
  const registry = getKindRegistry(ctx.config);
@@ -1027,8 +1083,7 @@ function approvedRequirements(ctx, task) {
1027
1083
  }
1028
1084
  function claimRequirements(ctx, task) {
1029
1085
  if (task.type !== "build" && task.type !== "qa") return [];
1030
- if (task.role === "product-manager") return [];
1031
- return [...existRequirements(task), ...approvedRequirements(ctx, task)];
1086
+ return [...existRequirements(ctx, task), ...approvedRequirements(ctx, task)];
1032
1087
  }
1033
1088
  function requirementSatisfied(ctx, req, matched) {
1034
1089
  if (req.level === "exist") return matched.length > 0;
@@ -1154,6 +1209,7 @@ var init_gates = __esm({
1154
1209
  init_derive();
1155
1210
  init_kind();
1156
1211
  init_lints();
1212
+ init_roles();
1157
1213
  }
1158
1214
  });
1159
1215
 
@@ -1800,11 +1856,7 @@ var init_artifact_commands = __esm({
1800
1856
  import { existsSync as existsSync6 } from "node:fs";
1801
1857
  import { join as join7 } from "node:path";
1802
1858
  function ownerRole(ctx, kind) {
1803
- for (const [role, kinds] of Object.entries(ctx.config.roleProduces)) {
1804
- if (kinds.includes(kind)) return role;
1805
- }
1806
- if (kind === "code") return "developer";
1807
- return null;
1859
+ return ownerRoleOf(ctx.config, kind);
1808
1860
  }
1809
1861
  function openReviewTargetKeys(ctx, artifactId) {
1810
1862
  const rows = ctx.db.prepare(
@@ -1948,15 +2000,20 @@ var init_sync_command = __esm({
1948
2000
  init_events();
1949
2001
  init_git();
1950
2002
  init_kind();
2003
+ init_roles();
1951
2004
  init_artifact_commands();
1952
2005
  }
1953
2006
  });
1954
2007
 
1955
2008
  // core/commands/task.commands.ts
2009
+ function getRoleRegistryOwner(ctx, kind) {
2010
+ return ownerRoleOf(ctx.config, kind) ?? "qa";
2011
+ }
1956
2012
  function createTask(ctx, p) {
1957
2013
  const type = p.type ?? "build";
1958
2014
  if (!VALID_TYPES.includes(type)) throw new Error(`\u65E0\u6548\u7684\u4EFB\u52A1\u7C7B\u578B: ${type},\u53EF\u9009\u503C: ${VALID_TYPES.join(", ")}`);
1959
- if (!VALID_ROLES.includes(p.role)) throw new Error(`\u65E0\u6548\u7684\u89D2\u8272: ${p.role},\u53EF\u9009\u503C: ${VALID_ROLES.join(", ")}`);
2015
+ const validRoles = Object.keys(getRoleRegistry(ctx.config));
2016
+ if (!validRoles.includes(p.role)) throw new Error(`\u65E0\u6548\u7684\u89D2\u8272: ${p.role},\u53EF\u9009\u503C: ${validRoles.join(", ")}`);
1960
2017
  const module = normalizeModule(p.module, ctx.config);
1961
2018
  const tx = ctx.db.transaction(() => {
1962
2019
  const result = ctx.db.prepare(
@@ -2051,11 +2108,12 @@ function updateTask(ctx, { id, status, operator, force = false }) {
2051
2108
  return { id, warnings };
2052
2109
  }
2053
2110
  function spawnFollowupQa(ctx, reworkTask) {
2111
+ const qaRole = getRoleRegistryOwner(ctx, "acceptance");
2054
2112
  const tx = ctx.db.transaction(() => {
2055
2113
  const result = ctx.db.prepare(
2056
2114
  `INSERT INTO tasks (module, role, endpoint, page, type, status, assignee, creator, content)
2057
- VALUES (?, 'qa', ?, ?, 'qa', 'pending', 'qa', 'system', ?)`
2058
- ).run(reworkTask.module, reworkTask.endpoint, reworkTask.page, `[\u590D\u9A8C] rework #${reworkTask.id} \u5DF2\u5B8C\u6210,\u8BF7\u91CD\u65B0\u9A8C\u6536`);
2115
+ VALUES (?, ?, ?, ?, 'qa', 'pending', ?, 'system', ?)`
2116
+ ).run(reworkTask.module, qaRole, reworkTask.endpoint, reworkTask.page, qaRole, `[\u590D\u9A8C] rework #${reworkTask.id} \u5DF2\u5B8C\u6210,\u8BF7\u91CD\u65B0\u9A8C\u6536`);
2059
2117
  const qaId = result.lastInsertRowid;
2060
2118
  logEvent(ctx.db, {
2061
2119
  entityType: "task",
@@ -2215,7 +2273,7 @@ function getTaskDetail(ctx, id) {
2215
2273
  }
2216
2274
  return { task, events, outputs, staleness: taskStaleness(ctx.db, id) };
2217
2275
  }
2218
- var VALID_STATUS, VALID_TYPES, VALID_ROLES;
2276
+ var VALID_STATUS, VALID_TYPES;
2219
2277
  var init_task_commands = __esm({
2220
2278
  "core/commands/task.commands.ts"() {
2221
2279
  "use strict";
@@ -2225,11 +2283,11 @@ var init_task_commands = __esm({
2225
2283
  init_git();
2226
2284
  init_gh();
2227
2285
  init_kind();
2286
+ init_roles();
2228
2287
  init_artifact_commands();
2229
2288
  init_sync_command();
2230
2289
  VALID_STATUS = ["pending", "in_progress", "completed", "cancelled"];
2231
2290
  VALID_TYPES = ["build", "review", "qa", "hotfix", "baseline", "legacy", "rework"];
2232
- VALID_ROLES = ["product-manager", "architect", "designer", "developer", "qa"];
2233
2291
  }
2234
2292
  });
2235
2293
 
@@ -2752,7 +2810,8 @@ var init_scan_command = __esm({
2752
2810
  // core/commands/qa.command.ts
2753
2811
  function recordQaResult(ctx, p) {
2754
2812
  const task = getTaskRow(ctx, p.id);
2755
- if (task.role !== "qa") throw new Error(`\u4EFB\u52A1 #${p.id} \u4E0D\u662F qa \u4EFB\u52A1`);
2813
+ const acceptanceRole = ownerRoleOf(ctx.config, "acceptance") ?? "qa";
2814
+ if (task.role !== acceptanceRole) throw new Error(`\u4EFB\u52A1 #${p.id} \u4E0D\u662F ${acceptanceRole} \u4EFB\u52A1`);
2756
2815
  if (task.assignee !== p.operator) throw new Error(`\u53EA\u6709\u6267\u884C\u4EBA\u624D\u80FD\u8BB0\u5F55\u9A8C\u6536\u7ED3\u679C`);
2757
2816
  if (p.result === "fail" && !p.reason?.trim()) throw new Error(`\u9A8C\u6536\u4E0D\u901A\u8FC7\u5FC5\u987B\u9644\u539F\u56E0,\u5B83\u5C06\u6210\u4E3A rework \u4EFB\u52A1\u7684\u5185\u5BB9`);
2758
2817
  const eventName = p.result === "pass" ? "qa_passed" : "qa_failed";
@@ -2780,11 +2839,12 @@ function recordQaResult(ctx, p) {
2780
2839
  }
2781
2840
  return { reworkTaskId: null };
2782
2841
  }
2842
+ const reworkRole = ownerRoleOf(ctx.config, "code") ?? "developer";
2783
2843
  const tx2 = ctx.db.transaction(() => {
2784
2844
  const result = ctx.db.prepare(
2785
2845
  `INSERT INTO tasks (module, role, endpoint, page, type, status, assignee, creator, content)
2786
- VALUES (?, 'developer', ?, ?, 'rework', 'pending', 'developer', 'system', ?)`
2787
- ).run(task.module, task.endpoint, task.page, `[\u8FD4\u5DE5] QA #${task.id} \u9A8C\u6536\u4E0D\u901A\u8FC7:${p.reason}`);
2846
+ VALUES (?, ?, ?, ?, 'rework', 'pending', ?, 'system', ?)`
2847
+ ).run(task.module, reworkRole, task.endpoint, task.page, reworkRole, `[\u8FD4\u5DE5] QA #${task.id} \u9A8C\u6536\u4E0D\u901A\u8FC7:${p.reason}`);
2788
2848
  const reworkId = result.lastInsertRowid;
2789
2849
  logEvent(ctx.db, {
2790
2850
  entityType: "task",
@@ -2804,6 +2864,7 @@ var init_qa_command = __esm({
2804
2864
  "core/commands/qa.command.ts"() {
2805
2865
  "use strict";
2806
2866
  init_events();
2867
+ init_roles();
2807
2868
  init_artifact_commands();
2808
2869
  init_task_commands();
2809
2870
  }
@@ -3019,35 +3080,25 @@ function planModule(ctx, moduleRaw, creator = "product-manager") {
3019
3080
  }
3020
3081
  const pagePrds = byKind("page-prd").filter((a) => a.endpoint && a.page && existsSync10(join12(ctx.root, a.path)));
3021
3082
  const endpoints = [...new Set(pagePrds.map((a) => a.endpoint))];
3022
- const desired = [
3023
- { role: "architect", endpoint: "common", page: null, type: "build", assignee: "architect", content: `\u8BBE\u8BA1 ${module} \u6A21\u5757\u6570\u636E\u5E93` },
3024
- { role: "architect", endpoint: "service", page: null, type: "build", assignee: "architect", content: `\u8BBE\u8BA1 ${module} \u6A21\u5757 API \u6587\u6863` },
3025
- { role: "developer", endpoint: "service", page: null, type: "build", assignee: "developer", content: `\u5B9E\u73B0 ${module} \u6A21\u5757 service \u7AEF` }
3026
- ];
3027
- for (const endpoint of endpoints) {
3028
- const hasDesignSystem = artifacts.some((a) => a.kind === "design-system" && a.endpoint === endpoint);
3029
- if (!hasDesignSystem) {
3030
- desired.push({
3031
- role: "designer",
3032
- endpoint,
3033
- page: null,
3034
- type: "build",
3035
- assignee: "designer",
3036
- content: `\u5EFA\u7ACB ${endpoint} \u7AEF\u8BBE\u8BA1\u7CFB\u7EDF(\u8BE5\u7AEF\u9996\u4E2A\u9875\u9762\u8BBE\u8BA1\u524D\u7F6E)`
3037
- });
3083
+ const registry = getRoleRegistry(ctx.config);
3084
+ const interp = (tpl, v) => tpl.replaceAll("{module}", v.module).replaceAll("{endpoint}", v.endpoint ?? "").replaceAll("{page}", v.page ?? "");
3085
+ const desired = [];
3086
+ for (const role of ctx.config.pipeline) {
3087
+ for (const d of registry[role]?.dispatch ?? []) {
3088
+ if (d.at === "module") {
3089
+ desired.push({ role, endpoint: d.endpoint ?? null, page: null, type: d.type ?? "build", assignee: role, content: interp(d.content, { module }) });
3090
+ } else if (d.at === "endpoint") {
3091
+ for (const endpoint of endpoints) {
3092
+ if (d.ifMissingKind && artifacts.some((a) => a.kind === d.ifMissingKind && a.endpoint === endpoint)) continue;
3093
+ desired.push({ role, endpoint, page: null, type: d.type ?? "build", assignee: role, content: interp(d.content, { module, endpoint }) });
3094
+ }
3095
+ } else {
3096
+ for (const prd of pagePrds) {
3097
+ desired.push({ role, endpoint: prd.endpoint, page: prd.page, type: d.type ?? "build", assignee: role, content: interp(d.content, { module, endpoint: prd.endpoint, page: prd.page }) });
3098
+ }
3099
+ }
3038
3100
  }
3039
3101
  }
3040
- for (const prd of pagePrds) {
3041
- desired.push(
3042
- { role: "designer", endpoint: prd.endpoint, page: prd.page, type: "build", assignee: "designer", content: `\u8BBE\u8BA1 ${prd.endpoint}/${prd.page} \u9875\u9762(\u63D0\u793A\u8BCD+\u539F\u578B)` },
3043
- { role: "developer", endpoint: prd.endpoint, page: prd.page, type: "build", assignee: "developer", content: `\u5B9E\u73B0 ${prd.endpoint}/${prd.page} \u9875\u9762` },
3044
- { role: "qa", endpoint: prd.endpoint, page: prd.page, type: "qa", assignee: "qa", content: `\u9A8C\u6536 ${prd.endpoint}/${prd.page} \u9875\u9762` }
3045
- );
3046
- }
3047
- const activeRoles = new Set(ctx.config.pipeline);
3048
- const filtered = desired.filter((d) => activeRoles.has(d.role));
3049
- desired.length = 0;
3050
- desired.push(...filtered);
3051
3102
  const exists = ctx.db.prepare(
3052
3103
  `SELECT COUNT(*) AS c FROM tasks
3053
3104
  WHERE module IS ? AND role = ? AND endpoint IS ? AND page IS ? AND type = ? AND status != 'cancelled'`
@@ -3092,6 +3143,7 @@ var init_plan_command = __esm({
3092
3143
  init_derive();
3093
3144
  init_events();
3094
3145
  init_kind();
3146
+ init_roles();
3095
3147
  init_task_commands();
3096
3148
  }
3097
3149
  });
@@ -3142,7 +3194,7 @@ var init_install_hooks_command = __esm({
3142
3194
  });
3143
3195
 
3144
3196
  // core/commands/gen-agents.command.ts
3145
- import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync6, readdirSync as readdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
3197
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
3146
3198
  import { dirname as dirname3, join as join14 } from "node:path";
3147
3199
  function expandPath(ctx, kind) {
3148
3200
  const spec = getKindRegistry(ctx.config)[kind];
@@ -3211,13 +3263,19 @@ function genAgents(ctx, templatesDir) {
3211
3263
  return content;
3212
3264
  };
3213
3265
  const adapters = resolvePlatforms(ctx.config.platforms);
3214
- const pipeline = new Set(ctx.config.pipeline);
3266
+ const registry = getRoleRegistry(ctx.config);
3215
3267
  const written = [];
3216
- for (const file of readdirSync5(dir)) {
3217
- if (!file.endsWith(".md")) continue;
3218
- const role = file.replace(/\.md$/, "");
3219
- if (!pipeline.has(role)) continue;
3220
- const tpl = parseTemplate(readFileSync6(join14(dir, file), "utf-8"));
3268
+ const projectTplDir = join14(ctx.root, "docs/workbench/templates/agents", lang);
3269
+ for (const role of [...new Set(ctx.config.pipeline)]) {
3270
+ if (!registry[role]) {
3271
+ throw new Error(`pipeline \u89D2\u8272 ${role} \u672A\u5728\u89D2\u8272\u6CE8\u518C\u8868\u4E2D\u5B9A\u4E49(\u5185\u7F6E\u6216 config.roles)`);
3272
+ }
3273
+ const candidates = [join14(projectTplDir, `${role}.md`), join14(dir, `${role}.md`)];
3274
+ const file = candidates.find((f) => existsSync12(f));
3275
+ if (!file) {
3276
+ throw new Error(`\u89D2\u8272 ${role} \u7F3A\u5C11 agent \u6A21\u677F:\u81EA\u5B9A\u4E49\u89D2\u8272\u8BF7\u63D0\u4F9B docs/workbench/templates/agents/${lang}/${role}.md`);
3277
+ }
3278
+ const tpl = parseTemplate(readFileSync6(file, "utf-8"));
3221
3279
  for (const adapter of adapters) {
3222
3280
  const memory = adapter.memoryBlock(role, lang);
3223
3281
  const spec = {
@@ -3242,6 +3300,7 @@ var init_gen_agents_command = __esm({
3242
3300
  "use strict";
3243
3301
  init_config();
3244
3302
  init_kind();
3303
+ init_roles();
3245
3304
  init_platforms();
3246
3305
  TRUST_PROTOCOL_ZH = `## \u4FE1\u4EFB\u534F\u8BAE(\u6700\u9AD8\u4F18\u5148\u7EA7)
3247
3306
 
@@ -3365,11 +3424,13 @@ function intakeIssues(ctx) {
3365
3424
  continue;
3366
3425
  }
3367
3426
  const isBug = issue.labels.some((l) => l.name.toLowerCase() === "bug");
3427
+ const bugRole = ctx.config.intake?.bugRole ?? "developer";
3428
+ const defaultRole = ctx.config.intake?.defaultRole ?? "product-manager";
3368
3429
  const id = createTask(ctx, {
3369
- role: isBug ? "developer" : "product-manager",
3370
- endpoint: isBug ? null : null,
3430
+ role: isBug ? bugRole : defaultRole,
3431
+ endpoint: null,
3371
3432
  type: isBug ? "hotfix" : "build",
3372
- assignee: isBug ? "developer" : "product-manager",
3433
+ assignee: isBug ? bugRole : defaultRole,
3373
3434
  creator: "intake",
3374
3435
  content: `[gh#${issue.number}] ${issue.title}
3375
3436
  ${issue.url}`,
@@ -3553,6 +3614,7 @@ __export(core_exports, {
3553
3614
  CONFIG_FILENAME: () => CONFIG_FILENAME,
3554
3615
  CURRENT_SCHEMA_VERSION: () => CURRENT_SCHEMA_VERSION,
3555
3616
  DEFAULT_KIND_REGISTRY: () => DEFAULT_KIND_REGISTRY,
3617
+ DEFAULT_ROLE_REGISTRY: () => DEFAULT_ROLE_REGISTRY,
3556
3618
  KIND_TIERS: () => KIND_TIERS,
3557
3619
  META_KINDS: () => META_KINDS,
3558
3620
  MIGRATIONS: () => MIGRATIONS,
@@ -3586,6 +3648,7 @@ __export(core_exports, {
3586
3648
  genAgents: () => genAgents,
3587
3649
  getAdapter: () => getAdapter,
3588
3650
  getKindRegistry: () => getKindRegistry,
3651
+ getRoleRegistry: () => getRoleRegistry,
3589
3652
  getTaskDetail: () => getTaskDetail,
3590
3653
  getTaskRow: () => getTaskRow,
3591
3654
  gitHead: () => gitHead,
@@ -3614,6 +3677,7 @@ __export(core_exports, {
3614
3677
  openWorkbench: () => openWorkbench,
3615
3678
  openWorkbenchAt: () => openWorkbenchAt,
3616
3679
  ownerRole: () => ownerRole,
3680
+ ownerRoleOf: () => ownerRoleOf,
3617
3681
  planModule: () => planModule,
3618
3682
  prototypeEndorsed: () => prototypeEndorsed,
3619
3683
  recordNote: () => recordNote,
@@ -3651,6 +3715,7 @@ var init_core = __esm({
3651
3715
  init_hash();
3652
3716
  init_events();
3653
3717
  init_kind();
3718
+ init_roles();
3654
3719
  init_platforms();
3655
3720
  init_derive();
3656
3721
  init_lints();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dawipong/opcflow",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Spec-anchored, drift-enforced execution layer for AI coding agents — artifact DAG, trust gates, multi-role pipeline; generates agents/MCP/hooks for Claude Code, Codex, OpenCode & Cursor.",
5
5
  "license": "MIT",
6
6
  "author": "Dawi",