deuk-agent-flow 4.0.37 → 5.0.2

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 (78) hide show
  1. package/CHANGELOG.ko.md +282 -0
  2. package/CHANGELOG.md +788 -120
  3. package/LICENSE +0 -0
  4. package/README.ko.md +97 -17
  5. package/README.md +108 -25
  6. package/bin/deuk-agent-flow.js +11 -13
  7. package/bin/deuk-agent-rule.js +1 -1
  8. package/bundled/README.md +3 -0
  9. package/bundled/deuk-agent-flow.vsix +0 -0
  10. package/core-rules/AGENTS.md +30 -118
  11. package/docs/architecture.ko.md +155 -2
  12. package/docs/architecture.md +155 -2
  13. package/docs/assets/agentflow-panel-skills.png +0 -0
  14. package/docs/assets/agentflow-panel.png +0 -0
  15. package/docs/how-it-works.ko.md +109 -52
  16. package/docs/how-it-works.md +128 -71
  17. package/docs/principles.ko.md +68 -68
  18. package/docs/principles.md +68 -68
  19. package/docs/usage-guide.ko.md +251 -212
  20. package/package.json +41 -34
  21. package/scripts/bundle-vscode-vsix.ts +67 -0
  22. package/scripts/{cli-args.mjs → cli-args.ts} +49 -12
  23. package/scripts/cli-init-commands.ts +99 -0
  24. package/scripts/cli-init-logic.ts +46 -0
  25. package/scripts/{cli-prompts.mjs → cli-prompts.ts} +19 -34
  26. package/scripts/{cli-rule-compiler.mjs → cli-rule-compiler.ts} +128 -112
  27. package/scripts/cli-skill-commands.ts +707 -0
  28. package/scripts/{cli-telemetry-commands.mjs → cli-telemetry-commands.ts} +25 -22
  29. package/scripts/cli-ticket-command-shared.ts +4 -0
  30. package/scripts/cli-ticket-commands.ts +3723 -0
  31. package/scripts/cli-ticket-index.ts +283 -0
  32. package/scripts/{cli-ticket-migration.mjs → cli-ticket-migration.ts} +44 -68
  33. package/scripts/cli-ticket-parser.ts +100 -0
  34. package/scripts/{cli-usage-commands.mjs → cli-usage-commands.ts} +325 -326
  35. package/scripts/cli-utils.ts +1560 -0
  36. package/scripts/cli.ts +695 -0
  37. package/scripts/{lint-md.mjs → lint-md.ts} +32 -42
  38. package/scripts/lint-rules.ts +203 -0
  39. package/scripts/{merge-logic.mjs → merge-logic.ts} +44 -44
  40. package/scripts/{plan-parser.mjs → plan-parser.ts} +53 -53
  41. package/templates/MODULE_RULE_TEMPLATE.md +11 -11
  42. package/templates/PROJECT_RULE.md +46 -47
  43. package/templates/TICKET_TEMPLATE.ko.md +48 -44
  44. package/templates/TICKET_TEMPLATE.md +48 -44
  45. package/templates/project-memory.md +19 -0
  46. package/templates/project-pilot/CONFORMANCE_GATE_TEMPLATE.md +25 -23
  47. package/templates/project-pilot/DRIFT_CHECKLIST.md +27 -19
  48. package/templates/project-pilot/FLOW_CONTRACT_TEMPLATE.md +26 -26
  49. package/templates/project-pilot/IMPLEMENTATION_MATRIX_TEMPLATE.md +30 -30
  50. package/templates/project-pilot/INTEGRATION_CONTRACT_TEMPLATE.md +26 -26
  51. package/templates/project-pilot/OWNER_MAP_TEMPLATE.md +15 -15
  52. package/templates/project-pilot/PROJECT_PILOT_RULE_TEMPLATE.md +34 -34
  53. package/templates/project-pilot/REFACTOR_CONTRACT_TEMPLATE.md +32 -32
  54. package/templates/project-pilot/REMEDIATION_PLAN_TEMPLATE.md +33 -33
  55. package/templates/rules.d/deukcontext-mcp.md +31 -31
  56. package/templates/rules.d/platform-coexistence.md +29 -29
  57. package/templates/skills/context-recall/SKILL.md +3 -1
  58. package/templates/skills/doc-sync/SKILL.md +111 -0
  59. package/templates/skills/generated-file-guard/SKILL.md +3 -1
  60. package/templates/skills/persona-maid/SKILL.md +65 -0
  61. package/templates/skills/project-pilot/SKILL.md +13 -52
  62. package/templates/skills/safe-refactor/SKILL.md +3 -1
  63. package/templates/skills/ticket-status-surface/SKILL.md +17 -0
  64. package/core-rules/GEMINI.md +0 -7
  65. package/docs/badges/npm-downloads.json +0 -8
  66. package/scripts/cli-init-commands.mjs +0 -1750
  67. package/scripts/cli-init-logic.mjs +0 -64
  68. package/scripts/cli-skill-commands.mjs +0 -201
  69. package/scripts/cli-ticket-commands.mjs +0 -2427
  70. package/scripts/cli-ticket-index.mjs +0 -298
  71. package/scripts/cli-ticket-parser.mjs +0 -209
  72. package/scripts/cli-utils.mjs +0 -602
  73. package/scripts/cli.mjs +0 -256
  74. package/scripts/lint-rules.mjs +0 -196
  75. package/scripts/publish-dual-npm.mjs +0 -141
  76. package/scripts/smoke-npm-docker.mjs +0 -102
  77. package/scripts/smoke-npm-local.mjs +0 -109
  78. package/scripts/update-download-badge.mjs +0 -103
package/scripts/cli.mjs DELETED
@@ -1,256 +0,0 @@
1
- #!/usr/bin/env node
2
- import { existsSync, rmSync } from "fs";
3
- import { dirname, join } from "path";
4
- import { fileURLToPath } from "url";
5
- import { parseArgs, parseTicketArgs, parseSkillArgs, parseTelemetryArgs, parseUsageArgs } from "./cli-args.mjs";
6
- import { formatInitCompletionMessage, runInit, runMerge } from "./cli-init-commands.mjs";
7
- import { runTicketCreate, runTicketList, runTicketUse, runTicketClose, runTicketArchive, runTicketDiscard, runTicketReports, runTicketMeta, runTicketConnect, runTicketRebuild, runTicketReportAttach, runTicketMove, runTicketNext, runTicketHotfix, runTicketStatus, runTicketGuard, runTicketHandoff, runTicketEvidenceCheck, runTicketEvidenceReport } from "./cli-ticket-commands.mjs";
8
- import { runTelemetry } from "./cli-telemetry-commands.mjs";
9
- import { runUsage } from "./cli-usage-commands.mjs";
10
- import { performUpgradeMigration } from "./cli-ticket-migration.mjs";
11
- import { loadInitConfig, writeInitConfig, checkUpdateNotifier, normalizeWorkflowMode, WORKFLOW_MODE_EXECUTE, AGENT_ROOT_DIR, resolveWorkflowMode, LEGACY_TEMPLATE_DIR, LEGACY_CONFIG_FILE } from "./cli-utils.mjs";
12
- import { runInteractive } from "./cli-prompts.mjs";
13
-
14
- const updatePromise = checkUpdateNotifier();
15
-
16
- const __dirname = dirname(fileURLToPath(import.meta.url));
17
- const pkgRoot = join(__dirname, "..");
18
- async function main() {
19
- const argv = process.argv.slice(2);
20
- const sub = argv[0];
21
- if (!sub || sub === "-h" || sub === "--help" || sub === "help") {
22
- printHelp();
23
- return;
24
- }
25
-
26
- const rest = argv.slice(1);
27
-
28
- if (sub === "ticket") {
29
- const action = rest[0];
30
- const opts = parseTicketArgs(rest.slice(1));
31
- if (!action || action === "-h" || action === "--help" || action === "help" || opts.help) {
32
- printHelp();
33
- return;
34
- }
35
- if (action === "create") await runTicketCreate(opts);
36
- else if (action === "list") await runTicketList(opts);
37
- else if (action === "use") await runTicketUse(opts);
38
- else if (action === "next") await runTicketNext(opts);
39
- else if (action === "evidence") await runTicketEvidenceCheck(opts);
40
- else if (action === "close") await runTicketClose(opts);
41
- else if (action === "archive") await runTicketArchive(opts);
42
- else if (action === "discard" || action === "delete") await runTicketDiscard(opts);
43
- else if (action === "reports") await runTicketReports(opts);
44
- else if (action === "meta") await runTicketMeta(opts);
45
- else if (action === "connect") await runTicketConnect(opts);
46
- else if (action === "rebuild") await runTicketRebuild(opts);
47
- else if (action === "move" || action === "step") await runTicketMove(opts);
48
- else if (action === "hotfix") await runTicketHotfix(opts);
49
- else if (action === "status") await runTicketStatus(opts);
50
- else if (action === "guard" || action === "context") await runTicketGuard(opts);
51
- else if (action === "handoff" || action === "continue") await runTicketHandoff(opts);
52
- else if (action === "report") {
53
- const subAction = rest[1];
54
- if (subAction === "attach") {
55
- const attachOpts = parseTicketArgs(rest.slice(2));
56
- await runTicketReportAttach(attachOpts);
57
- } else if (opts.claim) {
58
- await runTicketEvidenceReport(opts);
59
- } else {
60
- await runTicketReports(opts);
61
- }
62
- }
63
- else if (action === "upgrade" || action === "migrate") {
64
- const count = performUpgradeMigration(opts.cwd, opts);
65
- console.log(`Migration complete: ${count} tickets upgraded.`);
66
- }
67
- else {
68
- console.error("Unknown ticket action: " + action);
69
- printHelp();
70
- }
71
- return;
72
- }
73
-
74
- if (sub === "telemetry") {
75
- const opts = parseTelemetryArgs(rest);
76
- await runTelemetry(opts);
77
- return;
78
- }
79
-
80
- if (sub === "usage") {
81
- const action = rest[0];
82
- const opts = parseUsageArgs(rest.slice(1));
83
- await runUsage(action, opts);
84
- return;
85
- }
86
-
87
- if (sub === "skill") {
88
- const action = rest[0];
89
- const opts = parseSkillArgs(rest.slice(1));
90
- const { runSkill } = await import("./cli-skill-commands.mjs");
91
- await runSkill(action, opts);
92
- return;
93
- }
94
-
95
- if (sub === "lint:md" || sub === "lint-md") {
96
- const { runMarkdownLint } = await import("./lint-md.mjs");
97
- runMarkdownLint(rest);
98
- return;
99
- }
100
-
101
- if (sub === "rules") {
102
- const action = rest[0];
103
- const opts = parseArgs(rest.slice(1));
104
- if (action === "audit") {
105
- const { runRulesAudit } = await import("./lint-rules.mjs");
106
- runRulesAudit(opts);
107
- return;
108
- }
109
- console.error("Unknown rules action: " + action);
110
- printHelp();
111
- return;
112
- }
113
-
114
- if (sub === "init" || sub === "merge") {
115
- const opts = parseArgs(rest);
116
- if (opts.help) {
117
- printHelp();
118
- return;
119
- }
120
-
121
- const saved = loadInitConfig(opts.cwd);
122
- if (saved && !opts.interactive) {
123
- // CLI flags (opts) take precedence over saved config
124
- for (const key in saved) {
125
- if (opts[key] === undefined) opts[key] = saved[key];
126
- }
127
- console.log(`Using saved config from ${AGENT_ROOT_DIR}/config.json (CLI overrides applied)`);
128
- }
129
-
130
- if (sub === "init") {
131
- await handleInit(opts, saved);
132
- } else {
133
- runMerge(opts, pkgRoot);
134
- }
135
- return;
136
- }
137
-
138
- console.error("Unknown command: " + sub);
139
- printHelp();
140
- }
141
-
142
- // Removed legacy migration runTicketMigrate
143
-
144
- async function handleInit(opts, saved) {
145
- if (opts.clean && !opts.dryRun) {
146
- console.log(`[CLEAN] Removing runtime template copies, legacy templates, and config...`);
147
- const templatesDir = join(opts.cwd, LEGACY_TEMPLATE_DIR);
148
- const runtimeTemplatesDir = join(opts.cwd, AGENT_ROOT_DIR, "templates");
149
- const configFile = join(opts.cwd, LEGACY_CONFIG_FILE);
150
- if (existsSync(templatesDir)) rmSync(templatesDir, { recursive: true, force: true });
151
- if (existsSync(runtimeTemplatesDir)) rmSync(runtimeTemplatesDir, { recursive: true, force: true });
152
- if (existsSync(configFile)) rmSync(configFile, { force: true });
153
- }
154
-
155
- if (!opts.interactive && !opts.nonInteractive && !saved) {
156
- // If no config and not interactive, prompt unless non-interactive
157
- await runInteractive(opts);
158
- } else if (opts.interactive) {
159
- await runInteractive(opts);
160
- }
161
-
162
- if (!opts.dryRun) writeInitConfig(opts.cwd, opts);
163
-
164
- const workflowMode = resolveWorkflowMode(opts, saved);
165
- if (!opts.dryRun && workflowMode !== WORKFLOW_MODE_EXECUTE) {
166
- console.log(`[WORKFLOW] Plan mode active. Re-run with --workflow execute or --approval approved to apply file mutations.`);
167
- return;
168
- }
169
-
170
- await runInit(opts, pkgRoot);
171
- console.log(formatInitCompletionMessage(opts.cwd, opts.dryRun));
172
- }
173
-
174
- function printHelp() {
175
- console.log(`DeukAgentFlow CLI - Generalization Rules & Ticket Management
176
-
177
- Usage:
178
- npx deuk-agent-flow init [options]
179
- npx deuk-agent-flow merge [options]
180
- npx deuk-agent-flow lint:md [--cwd <path>] [files...]
181
- npx deuk-agent-flow rules audit [--compact|--json]
182
- npx deuk-agent-flow skill <list|add|expose|lint> [options]
183
- npx deuk-agent-flow ticket <create|evidence|list|status|guard|context|handoff|continue|use|close|archive|discard|delete|reports|migrate|upgrade|meta|connect|move> [options]
184
- npx deuk-agent-flow telemetry <log|sync|summary|migrate> [options]
185
- npx deuk-agent-flow usage <set|status|advise> [options]
186
-
187
- Options:
188
- --cwd <path> Target repo root
189
- --dry-run Print actions without writing
190
- --non-interactive CI/scripts mode: no prompts
191
- --tag <id> Custom marker ID (default: deuk-agent-rule)
192
- --agents <mode> inject | skip | overwrite
193
- --cursorrules <mode> inject | skip | overwrite
194
- --workspace-kind <k> planning | coding | systems | research | mixed | other
195
- --stack <name> none | web | backend | unity | data | infra | hybrid | other
196
- --context-mcp <mode> skip | configured | later
197
- --workflow <mode> plan | execute
198
- --approval <state> pending | approved (alias for workflow)
199
- --docs-language <lang> auto | ko | en
200
- --json Output result in JSON format
201
- --remote <url> Temporary pipeline URL
202
- --sync Force enable remote sync
203
- --no-sync Force disable remote sync
204
-
205
- Skill Options:
206
- --skill, --id <name> Skill ID (safe-refactor|generated-file-guard|context-recall|project-pilot)
207
- --platform <name> Exposure target (claude|cursor)
208
-
209
- Ticket Options:
210
- --topic, --id <name> Ticket topic slug or ID
211
- --group <name> Ticket group (sub|main|discussion)
212
- --project <name> Project filter (DeukUI|DeukAgentFlow)
213
- --submodule <name> Submodule filter (DeukPack|DeukUI)
214
- --docs-language <lang> auto | ko | en
215
- --evidence <text> Provide Phase 0 RAG evidence summary
216
- --claim <text> Validate or report only from ticket evidence matching this claim
217
- --skip-phase0 Bypass Phase 0 RAG validation
218
- --plan-body <text> Create ticket with filled Phase 1 markdown body
219
- --plan-body-file <p> Read filled Phase 1 markdown from a file, or '-' for stdin
220
- --content-file <path> Read extra ticket context from a file, or '-' for stdin
221
- --require-filled Enforce non-placeholder APC and compact plan content before create succeeds
222
- --allow-placeholder Opt out of strict create guard (legacy behavior)
223
- --ticket-started Confirm the clickable ticket-start line was shared before guard/context
224
- --ticket-reviewed Confirm the durable ticket body was reopened and reviewed before guard/context
225
- --compact Prefer one-line ticket outputs in automation flows
226
- --status-detail Include detailed reasons in ticket status output
227
- --handoff Emit compact handoff output for session continuation
228
- --phase <number> Explicitly set the phase number (e.g., --phase 2)
229
- --next Move to the next phase
230
- --latest, -l Use most recent ticket (default if no topic)
231
- --path-only Print only the file path
232
- --json Output result in JSON format
233
-
234
- Usage Options:
235
- --platform <name> Platform name (Codex/Copilot supported)
236
- --client <name> Client label for usage state/output
237
- --agent-id <id> Agent identifier for per-agent tracking
238
- --weekly-remaining <pct> Remaining weekly percentage (0-100)
239
- --five-hour-remaining <pct> Remaining 5-hour percentage (0-100)
240
- --weekly-reset <text> Weekly reset time label
241
- --five-hour-reset <text> 5-hour reset time label
242
- --task-grade <grade> Task grade (S|A|B|C)
243
- --task <label> Optional task label for advice output
244
- --turn-count <n> Conversation turn count for split advice
245
- --linked-ticket-count <n> Linked ticket count for split advice
246
- --cross-workspace Mark the conversation as cross-workspace
247
- `);
248
- }
249
-
250
- main().then(async () => {
251
- await updatePromise;
252
- }).catch(async err => {
253
- await updatePromise;
254
- console.error(err.message || err);
255
- process.exit(1);
256
- });
@@ -1,196 +0,0 @@
1
- import { existsSync, readFileSync } from "fs";
2
- import { join } from "path";
3
-
4
- function extractSection(rules, heading) {
5
- const pattern = new RegExp(`(^## ${heading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\n[\\s\\S]*?)(?=^## |\\z)`, "m");
6
- return rules.match(pattern)?.[1] || "";
7
- }
8
-
9
- function nonEmptyLineCount(text) {
10
- return String(text || "").split(/\r?\n/).filter((line) => line.trim()).length;
11
- }
12
-
13
- const RULE_CHECKS = [
14
- {
15
- code: "DR-KERNEL-01",
16
- message: "Compact kernel must keep ticket-first and tool-contract invariants at the top of the core rules.",
17
- test: (rules) => /## Compact Kernel/i.test(rules)
18
- && nonEmptyLineCount(extractSection(rules, "Compact Kernel")) <= 10
19
- && /Tools own detail/i.test(rules)
20
- && /No ticket, no writes/i.test(rules)
21
- && /User requirements are ticket-first/i.test(rules)
22
- && /Existing-ticket close actions are not new-ticket triggers/i.test(rules)
23
- && /cause, analysis, and design\/approach/i.test(rules)
24
- && /approval or correction creates another ticket update loop/i.test(rules)
25
- && /reopen and review the durable ticket body/i.test(rules)
26
- && /wait for explicit user approval/i.test(rules)
27
- && /Every phase must request and satisfy the tool-provided contract/i.test(rules)
28
- && /Phase state has two records/i.test(rules)
29
- && /deuk-agent-flow ticket guard/i.test(rules)
30
- && /explicit approval validated by `deuk-agent-flow ticket guard`/i.test(rules)
31
- && /Verification is mandatory/i.test(rules)
32
- && /Completion reports go in the ticket first/i.test(rules)
33
- && /terse TDW feedback only/i.test(rules)
34
- && /never bypass ticket, scope, generated-file, or verification gates/i.test(rules)
35
- && /Shortcut regression guard/i.test(rules)
36
- && /temporary passes, bypasses, semantic shrinkage, and language-specific patch branches/i.test(rules)
37
- && /Shared-contract guard/i.test(rules)
38
- && /Ticket creation failures are hard stops/i.test(rules)
39
- && /do not call `set_workflow_context`/i.test(rules)
40
- },
41
- {
42
- code: "DR-TOKEN-01",
43
- message: "Low-token mode must stay quiet and compact.",
44
- test: (rules) => /Silent-by-default is mandatory/i.test(rules)
45
- && /Keep chat compact/i.test(rules)
46
- && /Final answers must be short but complete enough/i.test(rules)
47
- && /Commentary surface map/i.test(rules)
48
- && /Running-surface contract/i.test(rules)
49
- && /CLI running-output contract/i.test(rules)
50
- && /must not print narrative labels, usage reminders, `file:\/\/` links, or progress text/i.test(rules)
51
- && /Shared interrupt contract/i.test(rules)
52
- && /When the user complains about verbosity, chatter, progress reports, or over-explaining/i.test(rules)
53
- && /Do not switch into meta labeling, terminology lessons, or general explanation/i.test(rules)
54
- && /짧게|매우 짧게|한 줄로|간단히/i.test(rules)
55
- && /one-sentence or bullet-only/i.test(rules)
56
- && /avoid repeating them in chat/i.test(rules)
57
- },
58
- {
59
- code: "DR-PRIORITY-01",
60
- message: "Rules must define pointer/core/project instruction precedence.",
61
- test: (rules) => /## 0\. Priority/i.test(rules)
62
- && /Global DeukAgentFlow pointer/i.test(rules)
63
- && /Local generated pointer\/spoke/i.test(rules)
64
- && /core-rules\/AGENTS\.md/i.test(rules)
65
- && /PROJECT_RULE\.md/i.test(rules)
66
- },
67
- {
68
- code: "DR-BOOT-01",
69
- message: "Boot sequence must load core rules, project rules, and ticket context.",
70
- test: (rules) => /Boot Sequence \(run once\)/i.test(rules)
71
- && /Read this file \(AGENTS\.md\)/i.test(rules)
72
- && /Read `PROJECT_RULE\.md`/i.test(rules)
73
- && /ticket-start line, reopen and review the durable ticket body, and stop while approval is pending/i.test(rules)
74
- && /approval\/correction in the ticket/i.test(rules)
75
- && /deuk-agent-flow ticket guard --topic <id> --ticket-started --ticket-reviewed --approval approved/i.test(rules)
76
- && /set_workflow_context\(project, ticket_id, phase\)/i.test(rules)
77
- && /explicit user approval/i.test(rules)
78
- },
79
- {
80
- code: "DR-TICKET-01",
81
- message: "First-turn and discovery behavior must stay ticket-first.",
82
- test: (rules) => /First-Turn Invariant/i.test(rules)
83
- && /Ticket Discovery \(1-CALL RULE\)/i.test(rules)
84
- && /create the ticket first/i.test(rules)
85
- && /reopen and review the durable ticket body/i.test(rules)
86
- && /wait for explicit user approval/i.test(rules)
87
- && /update the ticket with that new input/i.test(rules)
88
- && /If that correction arrives during `approved_execution`, `command_running`, or `search_running`, treat it as an immediate interrupt/i.test(rules)
89
- && /If the user asks only for commit\/report\/archive\/close/i.test(rules)
90
- && /reuse that ticket and continue through Phase 4/i.test(rules)
91
- && /create a new ticket only if the user adds new implementation, new investigation, or a broader scope/i.test(rules)
92
- && /deuk-agent-flow ticket guard --ticket-started --ticket-reviewed --approval approved/i.test(rules)
93
- && /do not run repo inspection commands/i.test(rules)
94
- && /deuk-agent-flow ticket create` or `deuk-agent-flow ticket use/i.test(rules)
95
- && /Do not start with `git status`, `rg`, `find`, diffs, or broad help output/i.test(rules)
96
- && /Do not use `deuk-agent-flow ticket list` for discovery/i.test(rules)
97
- },
98
- {
99
- code: "DR-CHANGE-01",
100
- message: "Phase contract must require tool-provided requirements and block shortcuts.",
101
- test: (rules) => /Phase Contract/i.test(rules)
102
- && /complete requirement bundle/i.test(rules)
103
- && /Required ticket fields\/tasks/i.test(rules)
104
- && /Scope boundaries, generated\/source mapping/i.test(rules)
105
- && /Do not invent a shortcut/i.test(rules)
106
- },
107
- {
108
- code: "DR-LIFECYCLE-01",
109
- message: "Lifecycle must cover phases, durable records, and compact chat.",
110
- test: (rules) => /Ticket Lifecycle/i.test(rules)
111
- && /Phase 0/i.test(rules)
112
- && /Phase 4/i.test(rules)
113
- && /cause, analysis, design\/approach/i.test(rules)
114
- && /findings, hypotheses, scope, compact plan, and phase contract/i.test(rules)
115
- && /verification outcome, completion report, residual risk, and a follow-up decision/i.test(rules)
116
- && /Keep chat compact once the ticket carries the durable record/i.test(rules)
117
- },
118
- {
119
- code: "DR-GATE-01",
120
- message: "Hard stops must block missing contracts, unsafe scope, and premature execution.",
121
- test: (rules) => /Hard Stops/i.test(rules)
122
- && /missing phase contract/i.test(rules)
123
- && /generated\/source uncertainty/i.test(rules)
124
- && /shared-interface changes/i.test(rules)
125
- && /Stop for shortcut regressions/i.test(rules)
126
- && /verification that proves only the workaround instead of the shared contract/i.test(rules)
127
- && /repo inspection started before ticket selection or creation/i.test(rules)
128
- && /same TDW failure family appears twice/i.test(rules)
129
- && /read-only until the ticket records findings/i.test(rules)
130
- },
131
- {
132
- code: "DR-HALT-01",
133
- message: "Kernel must still define halt conditions and file guards.",
134
- test: (rules) => /Hard Stops/i.test(rules)
135
- && /generated\/source uncertainty/i.test(rules)
136
- && /missing tests/i.test(rules)
137
- },
138
- {
139
- code: "DR-CHURN-01",
140
- message: "Repeated symptom fixes must trigger stabilization instead of ticket churn.",
141
- test: (rules) => /Hard Stops/i.test(rules)
142
- && /stabilization or root-cause ticket/i.test(rules)
143
- && /same failure family/i.test(rules)
144
- },
145
- {
146
- code: "DR-CLI-01",
147
- message: "Tool delegation and CLI ownership must stay explicit.",
148
- test: (rules) => /Tool Delegation/i.test(rules)
149
- && /Use `rg`\/`rg --files` first/i.test(rules)
150
- && /Use MCP\/RAG only when local evidence is insufficient/i.test(rules)
151
- && /Let CLI own lifecycle enforcement, claim checks, reports, and audits/i.test(rules)
152
- && /AgentFlow Skill Status/i.test(rules)
153
- && /deuk-agent-flow skill list/i.test(rules)
154
- && /rules audit/i.test(rules)
155
- }
156
- ];
157
-
158
- export function auditRules(cwd = process.cwd()) {
159
- const rulesPath = join(cwd, "core-rules", "AGENTS.md");
160
- if (!existsSync(rulesPath)) {
161
- return {
162
- ok: false,
163
- path: rulesPath,
164
- violations: [{ code: "DR-RULES-00", message: "core-rules/AGENTS.md not found" }]
165
- };
166
- }
167
-
168
- const rules = readFileSync(rulesPath, "utf8");
169
- const violations = RULE_CHECKS
170
- .filter((check) => !check.test(rules))
171
- .map(({ code, message }) => ({ code, message }));
172
-
173
- return { ok: violations.length === 0, path: rulesPath, violations };
174
- }
175
-
176
- export function runRulesAudit(opts = {}) {
177
- const result = auditRules(opts.cwd || process.cwd());
178
- if (opts.json) {
179
- console.log(JSON.stringify(result, null, 2));
180
- } else if (opts.compact) {
181
- console.log(result.ok ? "rules:audit ok" : `rules:audit failed ${result.violations.length}`);
182
- } else if (result.ok) {
183
- console.log("rules:audit ok");
184
- } else {
185
- console.error("rules:audit failed");
186
- for (const violation of result.violations) {
187
- console.error(`${violation.code}: ${violation.message}`);
188
- }
189
- }
190
-
191
- if (!result.ok) {
192
- throw new Error(`rules audit failed: ${result.violations.map((v) => v.code).join(", ")}`);
193
- }
194
-
195
- return result;
196
- }
@@ -1,141 +0,0 @@
1
- #!/usr/bin/env node
2
- import { readFileSync, writeFileSync } from "fs";
3
- import { dirname, join } from "path";
4
- import { spawnSync } from "child_process";
5
- import { fileURLToPath } from "url";
6
-
7
- const __dirname = dirname(fileURLToPath(import.meta.url));
8
- const rootDir = join(__dirname, "..");
9
- const aliasDir = join(rootDir, "packages", "deuk-agent-rule");
10
-
11
- export function buildAliasPackageJson(rootPkg, currentAliasPkg = {}) {
12
- const version = rootPkg.version;
13
- return {
14
- ...currentAliasPkg,
15
- name: "deuk-agent-rule",
16
- version,
17
- description: "Compatibility wrapper for legacy deuk-agent-rule installs.",
18
- keywords: [
19
- "agents-md",
20
- "agent-flow",
21
- "agent-workflow",
22
- "ai-guardrails",
23
- "agent-guardrails",
24
- "deuk-family",
25
- ],
26
- license: rootPkg.license || currentAliasPkg.license || "Apache-2.0",
27
- repository: rootPkg.repository,
28
- bugs: rootPkg.bugs,
29
- homepage: rootPkg.homepage,
30
- files: ["bin/**/*", "README.md"],
31
- bin: {
32
- "deuk-agent-rule": "./bin/deuk-agent-rule.js",
33
- deukagentrule: "./bin/deuk-agent-rule.js",
34
- },
35
- engines: rootPkg.engines || currentAliasPkg.engines || { node: ">=18" },
36
- dependencies: {
37
- "deuk-agent-flow": version,
38
- },
39
- };
40
- }
41
-
42
- function readJson(path) {
43
- return JSON.parse(readFileSync(path, "utf8"));
44
- }
45
-
46
- function writeJson(path, value) {
47
- writeFileSync(path, JSON.stringify(value, null, 2) + "\n", "utf8");
48
- }
49
-
50
- function run(command, args, cwd) {
51
- const shown = [command, ...args].join(" ");
52
- console.log(`\n$ ${shown}`);
53
- const result = spawnSync(command, args, { cwd, stdio: "inherit" });
54
- if (result.status !== 0) {
55
- process.exit(result.status || 1);
56
- }
57
- }
58
-
59
- export function syncAliasPackageJson(paths = {}) {
60
- const rootPackagePath = paths.rootPackagePath || join(rootDir, "package.json");
61
- const aliasPackagePath = paths.aliasPackagePath || join(aliasDir, "package.json");
62
- const rootPkg = readJson(rootPackagePath);
63
- const aliasPkg = readJson(aliasPackagePath);
64
- const nextAliasPkg = buildAliasPackageJson(rootPkg, aliasPkg);
65
- writeJson(aliasPackagePath, nextAliasPkg);
66
- return nextAliasPkg;
67
- }
68
-
69
- function parseArgs(argv) {
70
- const opts = {
71
- dryRun: false,
72
- access: "public",
73
- tag: null,
74
- otp: null,
75
- skipTests: false,
76
- skipSmoke: false,
77
- aliasOnly: false,
78
- };
79
-
80
- for (let i = 0; i < argv.length; i += 1) {
81
- const arg = argv[i];
82
- if (arg === "--dry-run") opts.dryRun = true;
83
- else if (arg === "--skip-tests") opts.skipTests = true;
84
- else if (arg === "--skip-smoke") opts.skipSmoke = true;
85
- else if (arg === "--alias-only") opts.aliasOnly = true;
86
- else if (arg === "--access") opts.access = argv[++i];
87
- else if (arg === "--tag") opts.tag = argv[++i];
88
- else if (arg === "--otp") opts.otp = argv[++i];
89
- else {
90
- throw new Error(`Unknown argument: ${arg}`);
91
- }
92
- }
93
-
94
- return opts;
95
- }
96
-
97
- function publishArgs(opts) {
98
- const args = ["publish", "--access", opts.access, "--ignore-scripts"];
99
- if (opts.tag) args.push("--tag", opts.tag);
100
- if (opts.otp) args.push("--otp", opts.otp);
101
- if (opts.dryRun) args.push("--dry-run");
102
- return args;
103
- }
104
-
105
- export function main(argv = process.argv.slice(2)) {
106
- if (process.env.npm_command === "publish" && process.env.npm_lifecycle_event === "publish") {
107
- console.log("Skipping scripts.publish during npm publish lifecycle.");
108
- return;
109
- }
110
-
111
- const opts = parseArgs(argv);
112
- const aliasPkg = syncAliasPackageJson();
113
-
114
- const packageLabel = opts.aliasOnly ? "deuk-agent-rule" : "deuk-agent-flow and deuk-agent-rule";
115
- console.log(`Publishing ${packageLabel} at ${aliasPkg.version}`);
116
- if (opts.dryRun) {
117
- console.log("Dry-run mode: npm will build and validate packages without registry writes.");
118
- }
119
-
120
- if (!opts.skipTests) {
121
- run("npm", ["test"], rootDir);
122
- }
123
- if (!opts.skipSmoke) {
124
- run("node", ["scripts/smoke-npm-local.mjs"], rootDir);
125
- }
126
-
127
- const args = publishArgs(opts);
128
- if (!opts.aliasOnly) {
129
- run("npm", args, rootDir);
130
- }
131
- run("npm", args, aliasDir);
132
- }
133
-
134
- if (process.argv[1] === fileURLToPath(import.meta.url)) {
135
- try {
136
- main();
137
- } catch (error) {
138
- console.error(error.message);
139
- process.exit(1);
140
- }
141
- }