@deftai/directive-core 0.90.0 → 0.91.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/doctor/openclaw-skills.d.ts +42 -8
  2. package/dist/doctor/openclaw-skills.js +281 -38
  3. package/dist/eval/health.d.ts +10 -1
  4. package/dist/eval/health.js +16 -16
  5. package/dist/init-deposit/hygiene.js +3 -0
  6. package/dist/init-deposit/init-deposit.d.ts +5 -0
  7. package/dist/init-deposit/init-deposit.js +37 -2
  8. package/dist/intake/github-auth-modes.d.ts +1 -1
  9. package/dist/intake/github-auth-modes.js +25 -3
  10. package/dist/intake/issue-ingest-cli.js +13 -0
  11. package/dist/intake/reconcile-issues-cli.js +13 -0
  12. package/dist/policy/plan-extensions.d.ts +10 -0
  13. package/dist/policy/plan-extensions.js +16 -0
  14. package/dist/pr-closing-keywords/detect.d.ts +13 -0
  15. package/dist/pr-closing-keywords/detect.js +73 -8
  16. package/dist/pr-closing-keywords/index.d.ts +2 -2
  17. package/dist/pr-closing-keywords/index.js +1 -1
  18. package/dist/pr-closing-keywords/main.js +119 -90
  19. package/dist/pr-closing-keywords/types.d.ts +10 -0
  20. package/dist/render/constants.d.ts +16 -0
  21. package/dist/render/constants.js +16 -1
  22. package/dist/render/export-spec.d.ts +7 -1
  23. package/dist/render/export-spec.js +51 -5
  24. package/dist/render/index.d.ts +3 -2
  25. package/dist/render/index.js +2 -2
  26. package/dist/render/roadmap-render.js +164 -60
  27. package/dist/render/scope-outlook.d.ts +5 -0
  28. package/dist/render/scope-outlook.js +3 -0
  29. package/dist/render/spec-render.d.ts +28 -2
  30. package/dist/render/spec-render.js +111 -14
  31. package/dist/render/text-utils.d.ts +6 -0
  32. package/dist/render/text-utils.js +23 -0
  33. package/dist/scm/binary.d.ts +3 -0
  34. package/dist/scm/binary.js +10 -2
  35. package/dist/scm/call.d.ts +5 -0
  36. package/dist/scm/call.js +5 -0
  37. package/dist/scm/index.d.ts +1 -0
  38. package/dist/scm/index.js +1 -0
  39. package/dist/scm/main.d.ts +5 -0
  40. package/dist/scm/main.js +27 -0
  41. package/dist/scm/readiness-cli.d.ts +24 -0
  42. package/dist/scm/readiness-cli.js +85 -0
  43. package/dist/scm/readiness.d.ts +104 -0
  44. package/dist/scm/readiness.js +421 -0
  45. package/dist/scope/batch-promote.d.ts +26 -0
  46. package/dist/scope/batch-promote.js +167 -0
  47. package/dist/scope/index.d.ts +1 -0
  48. package/dist/scope/index.js +1 -0
  49. package/dist/scope/main.d.ts +2 -0
  50. package/dist/scope/main.js +58 -7
  51. package/dist/scope/wip-cap-check.d.ts +6 -0
  52. package/dist/scope/wip-cap-check.js +14 -2
  53. package/dist/session/session-start.d.ts +7 -0
  54. package/dist/session/session-start.js +54 -0
  55. package/dist/triage/welcome/index.d.ts +1 -1
  56. package/dist/triage/welcome/index.js +1 -1
  57. package/dist/triage/welcome/onboard.js +7 -1
  58. package/dist/triage/welcome/prior-state.d.ts +7 -0
  59. package/dist/triage/welcome/prior-state.js +16 -2
  60. package/dist/triage/welcome/writers.d.ts +10 -0
  61. package/dist/triage/welcome/writers.js +72 -2
  62. package/package.json +3 -3
@@ -7,12 +7,14 @@
7
7
  */
8
8
  import { existsSync, mkdirSync, readFileSync } from "node:fs";
9
9
  import { homedir, platform } from "node:os";
10
- import { join, resolve } from "node:path";
10
+ import { basename, join, resolve } from "node:path";
11
11
  import { assertDepositContained } from "../deposit/contain.js";
12
12
  import { copyTree } from "../deposit/copy-tree.js";
13
13
  import { prunePythonArtifactsFromDeposit } from "../deposit/python-free.js";
14
14
  import { resolveInstalledContentRoot } from "../deposit/resolve-content.js";
15
15
  import { readCorePackageVersion } from "../engine-version.js";
16
+ import { renderProjectDefinition } from "../render/project-render.js";
17
+ import { removeStaleMigratedFrameworkNarrative } from "../xbrief-migrate/migrate-project.js";
16
18
  import { writeAgentHookDeposit } from "./agent-hooks.js";
17
19
  import { ensureInitGitignoreLines, reconstituteDepositFromContent } from "./gitignore.js";
18
20
  import { depositStagePaths, printCommitGuidance } from "./hygiene.js";
@@ -20,6 +22,7 @@ import { buildLegacyRefusalJson, buildLegacyRefusalMessage, detectLegacyLayout,
20
22
  import { printMigrateNudgeIfNeeded } from "./migrate.js";
21
23
  import { ensurePrettierIgnoreLines } from "./prettierignore.js";
22
24
  import { CANONICAL_INSTALL_ROOT, depositNeutralization, ensureTaskfile, writeAgentsMd, writeAgentsSkills, writeConsumerGitHooks, writeConsumerVbrief, writeInstallManifest, } from "./scaffold.js";
25
+ import { syncBareVersionMarker } from "./xbrief-projections.js";
23
26
  export function parseInitArgv(canonicalArgv, userArgv = []) {
24
27
  const args = [...canonicalArgv, ...userArgv];
25
28
  let projectDir = process.cwd();
@@ -113,10 +116,36 @@ export function printNextSteps(result, io) {
113
116
  io.printf(` 1. Open your AI coding assistant in ${result.projectDir}\n`);
114
117
  io.printf(" 2. Deft skill auto-discovery is partially implemented — if your agent doesn't\n");
115
118
  io.printf(' start setup automatically, tell it: "Use AGENTS.md"\n');
116
- io.printf(" 3. On first session, the agent will guide you through creating USER.md and PROJECT-DEFINITION.vbrief.json\n");
119
+ io.printf(" 3. On first session, the agent will guide you through USER.md (if missing).\n");
120
+ io.printf(" 4. PROJECT-DEFINITION is seeded at init (#3013) — run `task project:render` once to refresh items from lifecycle folders; do not multi-turn invent project identity.\n");
117
121
  printMigrateNudgeIfNeeded(result.projectDir, io);
118
122
  io.printf("\n");
119
123
  }
124
+ /**
125
+ * Ensure a minimal render-ready PROJECT-DEFINITION exists after lifecycle dirs
126
+ * are deposited (#3013 / epic #3009). Idempotent: never overwrites existing identity.
127
+ */
128
+ export function seedMinimalProjectDefinition(projectDir, io) {
129
+ const xbriefDir = join(projectDir, "xbrief");
130
+ const legacyDir = join(projectDir, "vbrief");
131
+ const root = existsSync(xbriefDir) ? xbriefDir : existsSync(legacyDir) ? legacyDir : null;
132
+ if (root === null) {
133
+ return false;
134
+ }
135
+ const isXbrief = basename(root) === "xbrief";
136
+ const projectDefPath = join(root, isXbrief ? "PROJECT-DEFINITION.xbrief.json" : "PROJECT-DEFINITION.vbrief.json");
137
+ if (existsSync(projectDefPath)) {
138
+ io.printf("PROJECT-DEFINITION already present — leaving identity intact (#3013).\n");
139
+ return false;
140
+ }
141
+ const [ok, message] = renderProjectDefinition(root);
142
+ if (ok) {
143
+ io.printf(`${message} (minimal seed for one-shot project:render; #3013)\n`);
144
+ return true;
145
+ }
146
+ io.printf(`PROJECT-DEFINITION seed skipped: ${message}\n`);
147
+ return false;
148
+ }
120
149
  export async function runInitDeposit(args, io, seams = {}) {
121
150
  const projectDir = args.projectDir;
122
151
  const deftDir = join(projectDir, CANONICAL_INSTALL_ROOT);
@@ -154,6 +183,12 @@ export async function runInitDeposit(args, io, seams = {}) {
154
183
  const skillsCreated = writeAgentsSkills(projectDir, io);
155
184
  await depositNeutralization(projectDir, io);
156
185
  await writeConsumerVbrief(projectDir, deftDir, io);
186
+ seedMinimalProjectDefinition(projectDir, io);
187
+ // Seeding PROJECT-DEFINITION.xbrief.json makes resolveLifecycleRoot succeed.
188
+ // Align the same consumer derivatives update repairs (#2595 / #2806) so
189
+ // init + git add -A is already clean under core.autocrlf=true (#2118 / #3013).
190
+ syncBareVersionMarker(projectDir, version);
191
+ removeStaleMigratedFrameworkNarrative(projectDir);
157
192
  writeConsumerGitHooks(projectDir, deftDir, io, seams.gitHooks);
158
193
  writeAgentHookDeposit(projectDir, io);
159
194
  let taskfileWired = false;
@@ -1,4 +1,4 @@
1
- import { type CompletedProcess } from "../scm/call.js";
1
+ import type { CompletedProcess } from "../scm/call.js";
2
2
  import { probeRuntimeCapabilities, type RuntimeCapabilityReport } from "./platform-capabilities.js";
3
3
  export declare const GITHUB_AUTH_MODE_INJECTED_TOKEN = "injected-token";
4
4
  export declare const GITHUB_AUTH_MODE_HOST_GH = "host-gh";
@@ -1,4 +1,4 @@
1
- import { call } from "../scm/call.js";
1
+ import { spawnSync } from "node:child_process";
2
2
  import { pyRepr } from "../scm/py-format.js";
3
3
  import { getPlatformCapabilities, probeRuntimeCapabilities, RUNTIME_MODE_CLOUD_HEADLESS, RUNTIME_MODE_CURSOR_NATIVE_SANDBOX, } from "./platform-capabilities.js";
4
4
  export const GITHUB_AUTH_MODE_INJECTED_TOKEN = "injected-token";
@@ -37,9 +37,31 @@ export function inferGithubAuthMode(runtimeReport) {
37
37
  }
38
38
  return GITHUB_AUTH_MODE_HOST_GH;
39
39
  }
40
+ /**
41
+ * Prefer live `gh` for auth/API validation. Do not route through scm.call /
42
+ * BINARY_PREFERENCE (ghx-first): ghx is a cached GET proxy and rejects multi-arg
43
+ * `api user --jq .login` forms used here (#2275 Greptile P1 / #954).
44
+ */
40
45
  function defaultRunGh(args, environ) {
41
- const verb = args[0];
42
- return call("github-issue", verb, args.slice(1), { env: environ, timeout: 30 });
46
+ const binary = "gh";
47
+ try {
48
+ const result = spawnSync(binary, [...args], {
49
+ env: environ,
50
+ encoding: "utf8",
51
+ timeout: 30_000,
52
+ stdio: ["ignore", "pipe", "pipe"],
53
+ });
54
+ return {
55
+ args: [binary, ...args],
56
+ returncode: result.status ?? 1,
57
+ stdout: typeof result.stdout === "string" ? result.stdout : "",
58
+ stderr: typeof result.stderr === "string" ? result.stderr : "",
59
+ };
60
+ }
61
+ catch (err) {
62
+ const message = err instanceof Error ? err.message : String(err);
63
+ return { args: [binary, ...args], returncode: 1, stdout: "", stderr: message };
64
+ }
43
65
  }
44
66
  function splitRepo(repo) {
45
67
  const idx = repo.indexOf("/");
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { fileURLToPath } from "node:url";
3
+ import { ScmStubError } from "../scm/errors.js";
4
+ import { requireScmReady } from "../scm/readiness.js";
3
5
  import { issueIngestMain } from "./issue-ingest.js";
4
6
  function parseArgs(argv) {
5
7
  const out = {};
@@ -25,6 +27,17 @@ function parseArgs(argv) {
25
27
  return out;
26
28
  }
27
29
  export function mainEntry(argv = process.argv.slice(2)) {
30
+ // #2275: fail loud when gh/auth is missing in this execution env.
31
+ try {
32
+ requireScmReady();
33
+ }
34
+ catch (err) {
35
+ if (err instanceof ScmStubError) {
36
+ process.stderr.write(`error: ${err.message}\n`);
37
+ return 2;
38
+ }
39
+ throw err;
40
+ }
28
41
  return issueIngestMain(parseArgs(argv));
29
42
  }
30
43
  if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { fileURLToPath } from "node:url";
3
+ import { ScmStubError } from "../scm/errors.js";
4
+ import { requireScmReady } from "../scm/readiness.js";
3
5
  import { reconcileMain } from "./reconcile-issues.js";
4
6
  function parseArgs(argv) {
5
7
  const out = {};
@@ -23,6 +25,17 @@ function parseArgs(argv) {
23
25
  return out;
24
26
  }
25
27
  export function mainEntry(argv = process.argv.slice(2)) {
28
+ // #2275: fail loud when gh/auth is missing in this execution env.
29
+ try {
30
+ requireScmReady();
31
+ }
32
+ catch (err) {
33
+ if (err instanceof ScmStubError) {
34
+ process.stderr.write(`error: ${err.message}\n`);
35
+ return 2;
36
+ }
37
+ throw err;
38
+ }
26
39
  return reconcileMain(parseArgs(argv));
27
40
  }
28
41
  if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
@@ -17,6 +17,14 @@
17
17
  export declare const PLAN_POLICY_KEY = "x-directive/policy";
18
18
  /** Namespaced directive scope-completion note key. */
19
19
  export declare const PLAN_COMPLETED_NOTE_KEY = "x-directive/completedNote";
20
+ /**
21
+ * Namespaced onboarding decision-provenance block (#1694 / #1695).
22
+ *
23
+ * Holds facts that must NOT be smuggled through policy value fields (e.g.
24
+ * `plan.policy.wipCap` presence must not mean "operator decided a WIP cap").
25
+ * Out-of-band from `x-directive/policy` so value and decision stay orthogonal.
26
+ */
27
+ export declare const PLAN_ONBOARDING_KEY = "x-directive/onboarding";
20
28
  /** Legacy bare policy key (pre-#1650); read-side fallback / write-side migration source. */
21
29
  export declare const LEGACY_PLAN_POLICY_KEY = "policy";
22
30
  /** Legacy bare completedNote key (pre-#1650); read-side fallback / write-side migration source. */
@@ -25,6 +33,8 @@ export declare const LEGACY_PLAN_COMPLETED_NOTE_KEY = "completedNote";
25
33
  export declare function readPlanPolicy(plan: unknown): unknown;
26
34
  /** Read the directive completedNote from a plan (namespaced first, bare fallback). */
27
35
  export declare function readPlanCompletedNote(plan: unknown): unknown;
36
+ /** Read the namespaced onboarding decision-provenance block (#1694). */
37
+ export declare function readPlanOnboarding(plan: unknown): unknown;
28
38
  /**
29
39
  * Rename a legacy bare `policy` key to the namespaced key in place when only
30
40
  * the bare key is present. No-op when the namespaced key already exists or no
@@ -17,6 +17,14 @@
17
17
  export const PLAN_POLICY_KEY = "x-directive/policy";
18
18
  /** Namespaced directive scope-completion note key. */
19
19
  export const PLAN_COMPLETED_NOTE_KEY = "x-directive/completedNote";
20
+ /**
21
+ * Namespaced onboarding decision-provenance block (#1694 / #1695).
22
+ *
23
+ * Holds facts that must NOT be smuggled through policy value fields (e.g.
24
+ * `plan.policy.wipCap` presence must not mean "operator decided a WIP cap").
25
+ * Out-of-band from `x-directive/policy` so value and decision stay orthogonal.
26
+ */
27
+ export const PLAN_ONBOARDING_KEY = "x-directive/onboarding";
20
28
  /** Legacy bare policy key (pre-#1650); read-side fallback / write-side migration source. */
21
29
  export const LEGACY_PLAN_POLICY_KEY = "policy";
22
30
  /** Legacy bare completedNote key (pre-#1650); read-side fallback / write-side migration source. */
@@ -42,6 +50,14 @@ export function readPlanPolicy(plan) {
42
50
  export function readPlanCompletedNote(plan) {
43
51
  return readPlanExtension(plan, PLAN_COMPLETED_NOTE_KEY, LEGACY_PLAN_COMPLETED_NOTE_KEY);
44
52
  }
53
+ /** Read the namespaced onboarding decision-provenance block (#1694). */
54
+ export function readPlanOnboarding(plan) {
55
+ const planObj = asPlanObject(plan);
56
+ if (planObj === null) {
57
+ return undefined;
58
+ }
59
+ return planObj[PLAN_ONBOARDING_KEY];
60
+ }
45
61
  /**
46
62
  * Rename a legacy bare `policy` key to the namespaced key in place when only
47
63
  * the bare key is present. No-op when the namespaced key already exists or no
@@ -1,5 +1,18 @@
1
1
  import type { Hit } from "./types.js";
2
2
  export declare const CLOSING_KEYWORD_RE: RegExp;
3
3
  export declare function renderHit(hit: Hit): string;
4
+ /** Layer 0 FP hits only (#737): keyword in negation / quotation / example / code-block / blockquote. */
4
5
  export declare function findHits(text: string, source: string): Hit[];
6
+ /**
7
+ * Intent-mode hits (#3015 class D): every closing-keyword + `#N` match, regardless of
8
+ * surrounding prose. GitHub closes on token presence; conditional English is ignored.
9
+ * reason is the FP category when present, otherwise `intent`.
10
+ */
11
+ export declare function findAllClosingKeywordHits(text: string, source: string): Hit[];
12
+ /**
13
+ * Body trailer `deft-close-intent: full` is intentionally NOT an authorization path.
14
+ * Intent-mode allowlist is CLI `--allow-close N,M` only (#3015 / Greptile class-D gate).
15
+ * Markdown examples must never suppress real closing-keyword findings.
16
+ */
17
+ export declare function hasFullCloseIntent(_text: string): boolean;
5
18
  //# sourceMappingURL=detect.d.ts.map
@@ -21,7 +21,8 @@ const EXAMPLE_MARKERS = [
21
21
  /\blike\b/i,
22
22
  ];
23
23
  const BLOCKQUOTE_RE = /^\s*>\s/m;
24
- const CODE_FENCE_RE = /^```/m;
24
+ /** CommonMark fenced code opener/closer at line start: 3+ backticks or 3+ tildes. */
25
+ const CODE_FENCE_LINE_RE = /^(?:`{3,}|~{3,})/;
25
26
  function findAllMatches(text, re) {
26
27
  const flags = re.flags.includes("g") ? re.flags : `${re.flags}g`;
27
28
  const pattern = new RegExp(re.source, flags);
@@ -41,10 +42,41 @@ function lineStartingAt(text, offset) {
41
42
  }
42
43
  return text.slice(lineStart, lineEnd);
43
44
  }
45
+ /**
46
+ * CommonMark fence stack: open and close must use the same character, and the
47
+ * closer length must be >= opener length. Mixed ``` / ~~~ or shorter closers
48
+ * do not pop the open fence.
49
+ */
44
50
  function isInsideCodeFence(text, offset) {
45
- const prefix = text.slice(0, offset);
46
- const matches = prefix.match(CODE_FENCE_RE);
47
- return matches !== null && matches.length % 2 === 1;
51
+ let openChar = null;
52
+ let openLen = 0;
53
+ let lineStart = 0;
54
+ while (lineStart < offset) {
55
+ let lineEnd = text.indexOf("\n", lineStart);
56
+ if (lineEnd === -1 || lineEnd > offset) {
57
+ lineEnd = Math.min(text.length, offset);
58
+ }
59
+ const line = text.slice(lineStart, lineEnd);
60
+ const m = CODE_FENCE_LINE_RE.exec(line);
61
+ if (m !== null) {
62
+ const fence = m[0] ?? "";
63
+ const ch = fence[0];
64
+ const len = fence.length;
65
+ if (openChar === null) {
66
+ openChar = ch;
67
+ openLen = len;
68
+ }
69
+ else if (ch === openChar && len >= openLen) {
70
+ openChar = null;
71
+ openLen = 0;
72
+ }
73
+ }
74
+ if (lineEnd >= offset) {
75
+ break;
76
+ }
77
+ lineStart = lineEnd + 1;
78
+ }
79
+ return openChar !== null;
48
80
  }
49
81
  function classifyHit(text, match) {
50
82
  const start = match.index ?? 0;
@@ -88,6 +120,12 @@ export function renderHit(hit) {
88
120
  return (` [${hit.source}] ${hit.reason}: ` +
89
121
  `"...${hit.context}..." -> ${hit.keyword} #${hit.issueNumber}`);
90
122
  }
123
+ function snippetAround(text, match) {
124
+ const snippetStart = Math.max(0, (match.index ?? 0) - 30);
125
+ const snippetEnd = Math.min(text.length, (match.index ?? 0) + match[0].length + 30);
126
+ return text.slice(snippetStart, snippetEnd).replace(/\n/g, " ");
127
+ }
128
+ /** Layer 0 FP hits only (#737): keyword in negation / quotation / example / code-block / blockquote. */
91
129
  export function findHits(text, source) {
92
130
  const hits = [];
93
131
  const re = new RegExp(CLOSING_KEYWORD_RE.source, CLOSING_KEYWORD_RE.flags);
@@ -95,14 +133,11 @@ export function findHits(text, source) {
95
133
  while (match !== null) {
96
134
  const category = classifyHit(text, match);
97
135
  if (category !== null) {
98
- const snippetStart = Math.max(0, (match.index ?? 0) - 30);
99
- const snippetEnd = Math.min(text.length, (match.index ?? 0) + match[0].length + 30);
100
- const context = text.slice(snippetStart, snippetEnd).replace(/\n/g, " ");
101
136
  hits.push({
102
137
  source,
103
138
  keyword: match[1] ?? "",
104
139
  issueNumber: Number(match[2]),
105
- context,
140
+ context: snippetAround(text, match),
106
141
  reason: category,
107
142
  });
108
143
  }
@@ -110,4 +145,34 @@ export function findHits(text, source) {
110
145
  }
111
146
  return hits;
112
147
  }
148
+ /**
149
+ * Intent-mode hits (#3015 class D): every closing-keyword + `#N` match, regardless of
150
+ * surrounding prose. GitHub closes on token presence; conditional English is ignored.
151
+ * reason is the FP category when present, otherwise `intent`.
152
+ */
153
+ export function findAllClosingKeywordHits(text, source) {
154
+ const hits = [];
155
+ const re = new RegExp(CLOSING_KEYWORD_RE.source, CLOSING_KEYWORD_RE.flags);
156
+ let match = re.exec(text);
157
+ while (match !== null) {
158
+ const category = classifyHit(text, match);
159
+ hits.push({
160
+ source,
161
+ keyword: match[1] ?? "",
162
+ issueNumber: Number(match[2]),
163
+ context: snippetAround(text, match),
164
+ reason: category ?? "intent",
165
+ });
166
+ match = re.exec(text);
167
+ }
168
+ return hits;
169
+ }
170
+ /**
171
+ * Body trailer `deft-close-intent: full` is intentionally NOT an authorization path.
172
+ * Intent-mode allowlist is CLI `--allow-close N,M` only (#3015 / Greptile class-D gate).
173
+ * Markdown examples must never suppress real closing-keyword findings.
174
+ */
175
+ export function hasFullCloseIntent(_text) {
176
+ return false;
177
+ }
113
178
  //# sourceMappingURL=detect.js.map
@@ -1,7 +1,7 @@
1
1
  export { EXIT_CONFIG_ERROR, EXIT_HITS_FOUND, EXIT_OK, GH_TIMEOUT_S, WINDOW_RADIUS, } from "./constants.js";
2
- export { findHits, renderHit } from "./detect.js";
2
+ export { findAllClosingKeywordHits, findHits, hasFullCloseIntent, renderHit, } from "./detect.js";
3
3
  export { defaultRunGh, fetchPrBody, fetchPrCommitMessages } from "./gh.js";
4
4
  export { readCommitsFile, readTextFile } from "./io.js";
5
5
  export { cmdPrCheckClosingKeywords, parseAllowList, parseArgs, run } from "./main.js";
6
- export type { Hit, ParsedArgs, RunGhFn, RunGhResult } from "./types.js";
6
+ export type { ClosingKeywordMode, Hit, ParsedArgs, RunGhFn, RunGhResult } from "./types.js";
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1,5 +1,5 @@
1
1
  export { EXIT_CONFIG_ERROR, EXIT_HITS_FOUND, EXIT_OK, GH_TIMEOUT_S, WINDOW_RADIUS, } from "./constants.js";
2
- export { findHits, renderHit } from "./detect.js";
2
+ export { findAllClosingKeywordHits, findHits, hasFullCloseIntent, renderHit, } from "./detect.js";
3
3
  export { defaultRunGh, fetchPrBody, fetchPrCommitMessages } from "./gh.js";
4
4
  export { readCommitsFile, readTextFile } from "./io.js";
5
5
  export { cmdPrCheckClosingKeywords, parseAllowList, parseArgs, run } from "./main.js";