deuk-agent-flow 4.0.37 → 4.2.7
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 +23 -0
- package/CHANGELOG.md +23 -0
- package/NOTICE.md +19 -0
- package/README.ko.md +2 -2
- package/README.md +2 -2
- package/core-rules/AGENTS.md +6 -4
- package/docs/npm-publish-guide.ko.md +70 -0
- package/docs/usage-guide.ko.md +2 -2
- package/package.json +18 -8
- package/scripts/cli-init-commands.mjs +48 -39
- package/scripts/cli-skill-commands.mjs +23 -12
- package/scripts/cli-ticket-command-shared.mjs +60 -0
- package/scripts/cli-ticket-commands.mjs +161 -114
- package/scripts/cli-ticket-index.mjs +41 -17
- package/scripts/cli-ticket-parser.mjs +4 -3
- package/scripts/lint-rules.mjs +1 -0
- package/scripts/smoke-npm-docker.mjs +1 -1
- package/scripts/smoke-npm-local.mjs +1 -0
- package/templates/TICKET_TEMPLATE.ko.md +3 -3
- package/templates/TICKET_TEMPLATE.md +3 -3
- package/templates/project-pilot/CONFORMANCE_GATE_TEMPLATE.md +2 -0
- package/templates/project-pilot/DRIFT_CHECKLIST.md +8 -0
- package/templates/skills/project-pilot/SKILL.md +17 -7
- package/templates/skills/safe-refactor/SKILL.md +1 -1
- package/docs/badges/npm-downloads.json +0 -8
|
@@ -12,6 +12,34 @@ const ARCHIVE_INDEX_RETENTION_MONTHS = 12;
|
|
|
12
12
|
const ARCHIVE_INDEX_MONTH_RE = /^INDEX\.archive\.(\d{4}-\d{2})\.json$/;
|
|
13
13
|
const ARCHIVE_INDEX_LEGACY_RE = /^INDEX\.archive\.json$/;
|
|
14
14
|
|
|
15
|
+
function parseNextTicketSequence(value) {
|
|
16
|
+
const raw = Number(value);
|
|
17
|
+
if (!Number.isInteger(raw) || raw < 1) return null;
|
|
18
|
+
return raw;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function maxTicketNumberFromEntries(entries = []) {
|
|
22
|
+
const newRe = /^([0-9]{3,4})-/;
|
|
23
|
+
let max = 0;
|
|
24
|
+
for (const e of (entries || [])) {
|
|
25
|
+
const id = String(e.id || '');
|
|
26
|
+
const m = id.match(newRe);
|
|
27
|
+
if (m) {
|
|
28
|
+
const n = parseInt(m[1], 10);
|
|
29
|
+
if (n > max) max = n;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return max;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function normalizeNextTicketSequence(nextTicketSequence, entries = []) {
|
|
36
|
+
const fallbackNum = maxTicketNumberFromEntries(entries);
|
|
37
|
+
const fallbackNext = fallbackNum < 9999 ? (fallbackNum + 1) : fallbackNum;
|
|
38
|
+
const parsed = parseNextTicketSequence(nextTicketSequence);
|
|
39
|
+
if (parsed === null) return fallbackNext || 1;
|
|
40
|
+
return Math.max(parsed, fallbackNext || 1);
|
|
41
|
+
}
|
|
42
|
+
|
|
15
43
|
function parseArchiveMonth(value) {
|
|
16
44
|
const match = String(value || "").match(/^(\d{4})-(\d{2})$/);
|
|
17
45
|
if (!match) return null;
|
|
@@ -77,7 +105,7 @@ function listArchiveIndexFiles(dir) {
|
|
|
77
105
|
|
|
78
106
|
function parseIndexFile(absPath) {
|
|
79
107
|
if (!existsSync(absPath)) {
|
|
80
|
-
return { version: 1, updatedAt: null, activeTicketId: null, entries: [] };
|
|
108
|
+
return { version: 1, updatedAt: null, activeTicketId: null, nextTicketSequence: 1, entries: [] };
|
|
81
109
|
}
|
|
82
110
|
try {
|
|
83
111
|
const j = JSON.parse(readFileSync(absPath, "utf8"));
|
|
@@ -90,11 +118,12 @@ function parseIndexFile(absPath) {
|
|
|
90
118
|
version: j.version || 1,
|
|
91
119
|
updatedAt: j.updatedAt ?? null,
|
|
92
120
|
activeTicketId: j.activeTicketId ?? null,
|
|
121
|
+
nextTicketSequence: parseNextTicketSequence(j.nextTicketSequence),
|
|
93
122
|
entries
|
|
94
123
|
};
|
|
95
124
|
} catch (err) {
|
|
96
125
|
console.error(`[ERROR] Failed to parse ${basename(absPath)} at ${absPath}:`, err.message);
|
|
97
|
-
return { version: 1, updatedAt: null, activeTicketId: null, entries: [], _corrupt: true };
|
|
126
|
+
return { version: 1, updatedAt: null, activeTicketId: null, nextTicketSequence: 1, entries: [], _corrupt: true };
|
|
98
127
|
}
|
|
99
128
|
}
|
|
100
129
|
|
|
@@ -151,6 +180,7 @@ export function readTicketIndexJson(cwd) {
|
|
|
151
180
|
version: main.version || archiveFiles[0]?.version || 1,
|
|
152
181
|
updatedAt: main.updatedAt ?? archiveFiles[0]?.updatedAt ?? null,
|
|
153
182
|
activeTicketId: main.activeTicketId ?? null,
|
|
183
|
+
nextTicketSequence: normalizeNextTicketSequence(main.nextTicketSequence, entries),
|
|
154
184
|
entries,
|
|
155
185
|
_corrupt: Boolean(main._corrupt || archiveFiles.some(file => file._corrupt))
|
|
156
186
|
};
|
|
@@ -168,6 +198,7 @@ export function writeTicketIndexJson(cwd, indexJson, opts = {}) {
|
|
|
168
198
|
|
|
169
199
|
const out = { ...indexJson };
|
|
170
200
|
delete out._corrupt;
|
|
201
|
+
out.nextTicketSequence = normalizeNextTicketSequence(out.nextTicketSequence, out.entries || []);
|
|
171
202
|
|
|
172
203
|
// Strip physical path snapshots before saving to enforce state-driven resolution
|
|
173
204
|
const entries = Array.isArray(out.entries) ? out.entries : [];
|
|
@@ -192,10 +223,11 @@ export function writeTicketIndexJson(cwd, indexJson, opts = {}) {
|
|
|
192
223
|
|
|
193
224
|
const desiredArchiveFiles = new Set();
|
|
194
225
|
for (const [yearMonth, bucket] of archiveBuckets.entries()) {
|
|
195
|
-
|
|
226
|
+
const archiveOut = {
|
|
196
227
|
version: out.version || 1,
|
|
197
228
|
updatedAt: out.updatedAt || new Date().toISOString(),
|
|
198
229
|
activeTicketId: null,
|
|
230
|
+
nextTicketSequence: out.nextTicketSequence,
|
|
199
231
|
entries: bucket.map(e => {
|
|
200
232
|
const { path, archiveDay, ...clean } = e;
|
|
201
233
|
return clean;
|
|
@@ -226,22 +258,14 @@ export function getHostnameSlug() {
|
|
|
226
258
|
}
|
|
227
259
|
}
|
|
228
260
|
|
|
229
|
-
export function computeNextTicketNumber(
|
|
261
|
+
export function computeNextTicketNumber(indexState) {
|
|
230
262
|
const hostname = getHostnameSlug();
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
const id = String(e.id || '');
|
|
235
|
-
const m = id.match(newRe);
|
|
236
|
-
if (m) {
|
|
237
|
-
const n = parseInt(m[1], 10);
|
|
238
|
-
if (n > max && n < 10000) max = n;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
return { num: max + 1, hostname };
|
|
263
|
+
const maybeEntries = Array.isArray(indexState) ? indexState : indexState?.entries;
|
|
264
|
+
const parsedNext = normalizeNextTicketSequence(indexState?.nextTicketSequence, maybeEntries);
|
|
265
|
+
return { num: parsedNext, hostname };
|
|
242
266
|
}
|
|
243
267
|
|
|
244
|
-
export function generateTicketId(topicSlug,
|
|
268
|
+
export function generateTicketId(topicSlug, indexState) {
|
|
245
269
|
const hostname = getHostnameSlug();
|
|
246
270
|
const slug = requireNonEmptySlug(topicSlug, "ticket topic");
|
|
247
271
|
const match = slug.match(/^(\d{3,4})-(.*)/);
|
|
@@ -250,7 +274,7 @@ export function generateTicketId(topicSlug, existingEntries) {
|
|
|
250
274
|
const restSlug = match[2].slice(0, 32);
|
|
251
275
|
return `${numStr}-${restSlug}-${hostname}`;
|
|
252
276
|
}
|
|
253
|
-
const { num } = computeNextTicketNumber(
|
|
277
|
+
const { num } = computeNextTicketNumber(indexState);
|
|
254
278
|
const numStr = String(num).padStart(3, '0');
|
|
255
279
|
const finalSlug = slug.slice(0, 32);
|
|
256
280
|
return `${numStr}-${finalSlug}-${hostname}`;
|
|
@@ -3,7 +3,7 @@ import { basename, dirname, join } from "path";
|
|
|
3
3
|
import {
|
|
4
4
|
AGENT_ROOT_DIR, TICKET_SUBDIR, TICKET_LIST_FILENAME,
|
|
5
5
|
toPosixPath, toRepoRelativePath, detectProjectFromBody, deriveTopicFromBaseName, normalizeTicketGroup,
|
|
6
|
-
parseFrontMatter, stringifyFrontMatter, discoverAllWorkspaces, detectConsumerTicketDir,
|
|
6
|
+
parseFrontMatter, stringifyFrontMatter, discoverAllWorkspaces, detectConsumerTicketDir, computeTicketPath,
|
|
7
7
|
ARCHIVE_YEAR_MONTH_RE, ARCHIVE_DAY_RE
|
|
8
8
|
} from "./cli-utils.mjs";
|
|
9
9
|
import { readTicketIndexJson, writeTicketIndexJson } from "./cli-ticket-index.mjs";
|
|
@@ -185,7 +185,8 @@ export function updateTicketEntryStatus(cwd, opts = {}) {
|
|
|
185
185
|
entry.updatedAt = new Date().toISOString();
|
|
186
186
|
|
|
187
187
|
// Sync status back to .md frontmatter to prevent rebuild reversion
|
|
188
|
-
const
|
|
188
|
+
const entryPath = entry.path || computeTicketPath(entry);
|
|
189
|
+
const absPath = join(cwd, entryPath);
|
|
189
190
|
if (existsSync(absPath)) {
|
|
190
191
|
try {
|
|
191
192
|
const body = readFileSync(absPath, "utf8");
|
|
@@ -199,7 +200,7 @@ export function updateTicketEntryStatus(cwd, opts = {}) {
|
|
|
199
200
|
writeFileSync(absPath, newBody, "utf8");
|
|
200
201
|
}
|
|
201
202
|
} catch (err) {
|
|
202
|
-
console.warn(`[WARNING] Failed to sync status to ${
|
|
203
|
+
console.warn(`[WARNING] Failed to sync status to ${entryPath}: ${err.message}`);
|
|
203
204
|
}
|
|
204
205
|
}
|
|
205
206
|
|
package/scripts/lint-rules.mjs
CHANGED
|
@@ -44,6 +44,7 @@ const RULE_CHECKS = [
|
|
|
44
44
|
test: (rules) => /Silent-by-default is mandatory/i.test(rules)
|
|
45
45
|
&& /Keep chat compact/i.test(rules)
|
|
46
46
|
&& /Final answers must be short but complete enough/i.test(rules)
|
|
47
|
+
&& /do not emit a second clickable link for that ticket/i.test(rules)
|
|
47
48
|
&& /Commentary surface map/i.test(rules)
|
|
48
49
|
&& /Running-surface contract/i.test(rules)
|
|
49
50
|
&& /CLI running-output contract/i.test(rules)
|
|
@@ -5,18 +5,18 @@
|
|
|
5
5
|
|
|
6
6
|
## Agent Permission Contract (APC)
|
|
7
7
|
|
|
8
|
-
[BOUNDARY]
|
|
8
|
+
### [BOUNDARY]
|
|
9
9
|
- 확인된 범위를 기준으로 정확한 수정 가능 모듈을 적습니다.
|
|
10
10
|
- 생성물, 무관한 공용 영역, 외부 루트처럼 건드리면 안 되는 범위를 적습니다.
|
|
11
11
|
- 이 범위를 지배하는 프로젝트 규칙과 코어 규칙을 적습니다.
|
|
12
12
|
|
|
13
|
-
[CONTRACT]
|
|
13
|
+
### [CONTRACT]
|
|
14
14
|
- 이 티켓이 의존하는 실제 입력, 근거, 아티팩트를 적습니다.
|
|
15
15
|
- 이 티켓이 만들어야 하는 실제 결과를 적습니다.
|
|
16
16
|
- 허용되는 부작용과 명시적으로 제외할 항목을 적습니다.
|
|
17
17
|
- 사용자가 명시적으로 요청한 경우가 아니면 테스트 작성/확장은 넣지 않습니다.
|
|
18
18
|
|
|
19
|
-
[PATCH PLAN]
|
|
19
|
+
### [PATCH PLAN]
|
|
20
20
|
- 확인된 로컬 맥락을 기준으로 정확한 구현 경로를 적습니다.
|
|
21
21
|
|
|
22
22
|
## Compact Plan
|
|
@@ -5,18 +5,18 @@
|
|
|
5
5
|
|
|
6
6
|
## Agent Permission Contract (APC)
|
|
7
7
|
|
|
8
|
-
[BOUNDARY]
|
|
8
|
+
### [BOUNDARY]
|
|
9
9
|
- Record the exact editable modules for this ticket using confirmed scope.
|
|
10
10
|
- Record forbidden/generated/unrelated areas that must stay untouched.
|
|
11
11
|
- Cite the governing project/core rule set that defines the boundary.
|
|
12
12
|
|
|
13
|
-
[CONTRACT]
|
|
13
|
+
### [CONTRACT]
|
|
14
14
|
- Record the concrete inputs, artifacts, or local evidence this ticket depends on.
|
|
15
15
|
- Record the concrete output expected from this ticket.
|
|
16
16
|
- Record allowed side effects and anything explicitly excluded.
|
|
17
17
|
- Do not include test creation or test expansion unless the user explicitly requested tests.
|
|
18
18
|
|
|
19
|
-
[PATCH PLAN]
|
|
19
|
+
### [PATCH PLAN]
|
|
20
20
|
- Record the exact implementation path for this ticket using confirmed local context.
|
|
21
21
|
|
|
22
22
|
## Compact Plan
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
| Stage | Command | Expected Result | Actual Result |
|
|
13
13
|
| --- | --- | --- | --- |
|
|
14
14
|
| structure | | | |
|
|
15
|
+
| metadata/manifest bypass | | | |
|
|
15
16
|
| build/test | | | |
|
|
16
17
|
| runtime/report | | | |
|
|
17
18
|
|
|
@@ -20,4 +21,5 @@
|
|
|
20
21
|
- Contract and implementation agree.
|
|
21
22
|
- Unsupported paths are explicit.
|
|
22
23
|
- Generated/runtime/report outputs match the intended owner path.
|
|
24
|
+
- Metadata/manifest/schema bypass findings are absent or recorded as blocking remediation.
|
|
23
25
|
- Residual risks are recorded.
|
|
@@ -7,6 +7,14 @@ Mark each line before implementation.
|
|
|
7
7
|
- [ ] No no-op or placeholder path is being counted as support.
|
|
8
8
|
- [ ] No generated artifact is being edited directly.
|
|
9
9
|
- [ ] No single-language patch is being presented as a shared fix.
|
|
10
|
+
- [ ] No provider/generator/template/report path hardcodes metadata-owned
|
|
11
|
+
protocol method spellings.
|
|
12
|
+
- [ ] No generated record format surface is hardcoded outside protocol contract
|
|
13
|
+
or generated-artifact manifest ownership.
|
|
14
|
+
- [ ] No schema JSON is embedded directly where schema metadata or manifest
|
|
15
|
+
ownership is required.
|
|
16
|
+
- [ ] No DpField-style helper is selected directly where shared runtime contract
|
|
17
|
+
ownership is required.
|
|
10
18
|
- [ ] No unsupported-by-contract path is being mislabeled as broken.
|
|
11
19
|
- [ ] No broken-entrypoint is being hidden as unsupported.
|
|
12
20
|
- [ ] Error behavior is explicit and testable.
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: project-pilot
|
|
3
|
-
summary: Apply the ProjectPilot Refactor Contract Kit before
|
|
3
|
+
summary: Apply the ProjectPilot Refactor Contract Kit before broad refactors.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# ProjectPilot
|
|
7
7
|
|
|
8
|
-
Authority: follow `core-rules/AGENTS.md`, the active ticket APC, Phase Gate,
|
|
8
|
+
Authority: follow `core-rules/AGENTS.md`, the active ticket APC, Phase Gate,
|
|
9
|
+
and project rules.
|
|
9
10
|
|
|
10
11
|
Use this skill when the task involves any of the following:
|
|
11
12
|
|
|
@@ -13,6 +14,8 @@ Use this skill when the task involves any of the following:
|
|
|
13
14
|
- protocol, serialization, transport, codec, or table lane work
|
|
14
15
|
- generated/runtime/report contract drift
|
|
15
16
|
- fallback, alias, helper, no-op, placeholder, or silent stub cleanup
|
|
17
|
+
- metadata, manifest, schema, generated-artifact, or report contract bypass
|
|
18
|
+
cleanup
|
|
16
19
|
- convention, naming, file layout, factory surface, or lifecycle unification
|
|
17
20
|
- repeated failure families where one local fix would hide shared contract drift
|
|
18
21
|
|
|
@@ -23,10 +26,14 @@ Use this skill when the task involves any of the following:
|
|
|
23
26
|
3. Define the refactor contract before proposing or making edits.
|
|
24
27
|
4. Build the implementation matrix across the relevant surfaces.
|
|
25
28
|
5. Classify drift as `C`, `P`, `S`, `B`, `U`, or `D`.
|
|
26
|
-
6. Identify source owners before touching source, generated, runtime, report,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
6. Identify source owners before touching source, generated, runtime, report,
|
|
30
|
+
or template files.
|
|
31
|
+
7. Identify metadata/manifest/schema contract bypasses before accepting
|
|
32
|
+
generated-output evidence.
|
|
33
|
+
8. Fill the drift checklist and reject shortcuts that hide drift.
|
|
34
|
+
9. Define the conformance gate in the ticket without creating tests unless the
|
|
35
|
+
user requested tests.
|
|
36
|
+
10. Only then split remediation tickets or implement scoped changes.
|
|
30
37
|
|
|
31
38
|
## Required Outputs
|
|
32
39
|
|
|
@@ -51,7 +58,8 @@ Use the shared ProjectPilot semantics and templates when available:
|
|
|
51
58
|
- `templates/project-pilot/CONFORMANCE_GATE_TEMPLATE.md`
|
|
52
59
|
- `templates/project-pilot/REMEDIATION_PLAN_TEMPLATE.md`
|
|
53
60
|
|
|
54
|
-
Consumer projects may keep only project-local pilot evidence and references.
|
|
61
|
+
Consumer projects may keep only project-local pilot evidence and references.
|
|
62
|
+
Shared ProjectPilot semantics and templates are owned by the upstream source of truth.
|
|
55
63
|
|
|
56
64
|
## Stop Conditions
|
|
57
65
|
|
|
@@ -59,5 +67,7 @@ Consumer projects may keep only project-local pilot evidence and references. Sha
|
|
|
59
67
|
- No implementation matrix or refactor contract can be stated clearly.
|
|
60
68
|
- Source-of-truth owner cannot be identified.
|
|
61
69
|
- A fix depends on generated direct edits or hidden fallback.
|
|
70
|
+
- A provider, generator, template, or report path hardcodes values that belong in
|
|
71
|
+
metadata, a manifest, schema contract, or shared conformance rule.
|
|
62
72
|
- Unsupported-by-contract and broken-entrypoint are not separated.
|
|
63
73
|
- Verification cannot prove the claimed alignment.
|