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.
@@ -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
- const archiveOut = {
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(existingEntries) {
261
+ export function computeNextTicketNumber(indexState) {
230
262
  const hostname = getHostnameSlug();
231
- const newRe = /^(\d{3,4})-/;
232
- let max = 0;
233
- for (const e of (existingEntries || [])) {
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, existingEntries) {
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(existingEntries);
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 absPath = join(cwd, entry.path);
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 ${entry.path}: ${err.message}`);
203
+ console.warn(`[WARNING] Failed to sync status to ${entryPath}: ${err.message}`);
203
204
  }
204
205
  }
205
206
 
@@ -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)
@@ -79,7 +79,7 @@ try {
79
79
  "test -f PROJECT_RULE.md",
80
80
  "test -d .deuk-agent",
81
81
  "test ! -d .deuk-agent/templates",
82
- "test -d .deuk-agent/skill-templates",
82
+ "test ! -d .deuk-agent/skill-templates",
83
83
  ].join("\n");
84
84
 
85
85
  run("docker", [
@@ -74,6 +74,7 @@ try {
74
74
  "bin/deuk-agent-flow.js",
75
75
  "bin/deuk-agent-rule.js",
76
76
  "scripts/cli.mjs",
77
+ "scripts/cli-ticket-command-shared.mjs",
77
78
  "scripts/cli-ticket-commands.mjs",
78
79
  "scripts/lint-md.mjs",
79
80
  "scripts/lint-rules.mjs",
@@ -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 cross-language, generated/runtime, or repeated-drift refactors.
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, and project rules.
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, or template files.
27
- 7. Fill the drift checklist and reject shortcuts that hide drift.
28
- 8. Define the conformance gate in the ticket without creating tests unless the user requested tests.
29
- 9. Only then split remediation tickets or implement scoped changes.
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. Shared ProjectPilot semantics and templates are owned by DeukAgentFlow.
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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: safe-refactor
3
- summary: Keep refactors small, scoped, and test-backed inside DeukAgentFlow TDW.
3
+ summary: Keep refactors small, scoped, and test-backed.
4
4
  ---
5
5
 
6
6
  # Safe Refactor
@@ -1,8 +0,0 @@
1
- {
2
- "schemaVersion": 1,
3
- "label": "deuk-flow downloads",
4
- "message": "1.8K/last-month",
5
- "color": "2f6fed",
6
- "namedLogo": "npm",
7
- "cacheSeconds": 86400
8
- }