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.
- package/CHANGELOG.ko.md +282 -0
- package/CHANGELOG.md +788 -120
- package/LICENSE +0 -0
- package/README.ko.md +97 -17
- package/README.md +108 -25
- package/bin/deuk-agent-flow.js +11 -13
- package/bin/deuk-agent-rule.js +1 -1
- package/bundled/README.md +3 -0
- package/bundled/deuk-agent-flow.vsix +0 -0
- package/core-rules/AGENTS.md +30 -118
- package/docs/architecture.ko.md +155 -2
- package/docs/architecture.md +155 -2
- package/docs/assets/agentflow-panel-skills.png +0 -0
- package/docs/assets/agentflow-panel.png +0 -0
- package/docs/how-it-works.ko.md +109 -52
- package/docs/how-it-works.md +128 -71
- package/docs/principles.ko.md +68 -68
- package/docs/principles.md +68 -68
- package/docs/usage-guide.ko.md +251 -212
- package/package.json +41 -34
- package/scripts/bundle-vscode-vsix.ts +67 -0
- package/scripts/{cli-args.mjs → cli-args.ts} +49 -12
- package/scripts/cli-init-commands.ts +99 -0
- package/scripts/cli-init-logic.ts +46 -0
- package/scripts/{cli-prompts.mjs → cli-prompts.ts} +19 -34
- package/scripts/{cli-rule-compiler.mjs → cli-rule-compiler.ts} +128 -112
- package/scripts/cli-skill-commands.ts +707 -0
- package/scripts/{cli-telemetry-commands.mjs → cli-telemetry-commands.ts} +25 -22
- package/scripts/cli-ticket-command-shared.ts +4 -0
- package/scripts/cli-ticket-commands.ts +3723 -0
- package/scripts/cli-ticket-index.ts +283 -0
- package/scripts/{cli-ticket-migration.mjs → cli-ticket-migration.ts} +44 -68
- package/scripts/cli-ticket-parser.ts +100 -0
- package/scripts/{cli-usage-commands.mjs → cli-usage-commands.ts} +325 -326
- package/scripts/cli-utils.ts +1560 -0
- package/scripts/cli.ts +695 -0
- package/scripts/{lint-md.mjs → lint-md.ts} +32 -42
- package/scripts/lint-rules.ts +203 -0
- package/scripts/{merge-logic.mjs → merge-logic.ts} +44 -44
- package/scripts/{plan-parser.mjs → plan-parser.ts} +53 -53
- package/templates/MODULE_RULE_TEMPLATE.md +11 -11
- package/templates/PROJECT_RULE.md +46 -47
- package/templates/TICKET_TEMPLATE.ko.md +48 -44
- package/templates/TICKET_TEMPLATE.md +48 -44
- package/templates/project-memory.md +19 -0
- package/templates/project-pilot/CONFORMANCE_GATE_TEMPLATE.md +25 -23
- package/templates/project-pilot/DRIFT_CHECKLIST.md +27 -19
- package/templates/project-pilot/FLOW_CONTRACT_TEMPLATE.md +26 -26
- package/templates/project-pilot/IMPLEMENTATION_MATRIX_TEMPLATE.md +30 -30
- package/templates/project-pilot/INTEGRATION_CONTRACT_TEMPLATE.md +26 -26
- package/templates/project-pilot/OWNER_MAP_TEMPLATE.md +15 -15
- package/templates/project-pilot/PROJECT_PILOT_RULE_TEMPLATE.md +34 -34
- package/templates/project-pilot/REFACTOR_CONTRACT_TEMPLATE.md +32 -32
- package/templates/project-pilot/REMEDIATION_PLAN_TEMPLATE.md +33 -33
- package/templates/rules.d/deukcontext-mcp.md +31 -31
- package/templates/rules.d/platform-coexistence.md +29 -29
- package/templates/skills/context-recall/SKILL.md +3 -1
- package/templates/skills/doc-sync/SKILL.md +111 -0
- package/templates/skills/generated-file-guard/SKILL.md +3 -1
- package/templates/skills/persona-maid/SKILL.md +65 -0
- package/templates/skills/project-pilot/SKILL.md +13 -52
- package/templates/skills/safe-refactor/SKILL.md +3 -1
- package/templates/skills/ticket-status-surface/SKILL.md +17 -0
- package/core-rules/GEMINI.md +0 -7
- package/docs/badges/npm-downloads.json +0 -8
- package/scripts/cli-init-commands.mjs +0 -1750
- package/scripts/cli-init-logic.mjs +0 -64
- package/scripts/cli-skill-commands.mjs +0 -201
- package/scripts/cli-ticket-commands.mjs +0 -2427
- package/scripts/cli-ticket-index.mjs +0 -298
- package/scripts/cli-ticket-parser.mjs +0 -209
- package/scripts/cli-utils.mjs +0 -602
- package/scripts/cli.mjs +0 -256
- package/scripts/lint-rules.mjs +0 -196
- package/scripts/publish-dual-npm.mjs +0 -141
- package/scripts/smoke-npm-docker.mjs +0 -102
- package/scripts/smoke-npm-local.mjs +0 -109
- 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
|
-
});
|
package/scripts/lint-rules.mjs
DELETED
|
@@ -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
|
-
}
|