@deftai/directive-core 0.89.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 (100) hide show
  1. package/dist/doctor/constants.d.ts +1 -1
  2. package/dist/doctor/constants.js +2 -0
  3. package/dist/doctor/flags.js +21 -1
  4. package/dist/doctor/index.d.ts +1 -0
  5. package/dist/doctor/index.js +1 -0
  6. package/dist/doctor/main.js +22 -0
  7. package/dist/doctor/openclaw-skills.d.ts +143 -0
  8. package/dist/doctor/openclaw-skills.js +706 -0
  9. package/dist/doctor/types.d.ts +11 -0
  10. package/dist/eval/health.d.ts +10 -1
  11. package/dist/eval/health.js +16 -16
  12. package/dist/hooks/dispatcher.js +20 -5
  13. package/dist/index.d.ts +1 -0
  14. package/dist/index.js +1 -0
  15. package/dist/init-deposit/hygiene.js +3 -0
  16. package/dist/init-deposit/init-deposit.d.ts +5 -0
  17. package/dist/init-deposit/init-deposit.js +37 -2
  18. package/dist/intake/github-auth-modes.d.ts +1 -1
  19. package/dist/intake/github-auth-modes.js +25 -3
  20. package/dist/intake/issue-ingest-cli.js +13 -0
  21. package/dist/intake/reconcile-issues-cli.js +13 -0
  22. package/dist/lifecycle/events.js +2 -0
  23. package/dist/lifecycle/index.d.ts +1 -0
  24. package/dist/lifecycle/index.js +1 -0
  25. package/dist/lifecycle/stats.d.ts +53 -0
  26. package/dist/lifecycle/stats.js +286 -0
  27. package/dist/policy/plan-extensions.d.ts +10 -0
  28. package/dist/policy/plan-extensions.js +16 -0
  29. package/dist/pr-closing-keywords/detect.d.ts +13 -0
  30. package/dist/pr-closing-keywords/detect.js +73 -8
  31. package/dist/pr-closing-keywords/index.d.ts +2 -2
  32. package/dist/pr-closing-keywords/index.js +1 -1
  33. package/dist/pr-closing-keywords/main.js +119 -90
  34. package/dist/pr-closing-keywords/types.d.ts +10 -0
  35. package/dist/release/spawn.js +13 -0
  36. package/dist/release-e2e/git-ops.d.ts +7 -0
  37. package/dist/release-e2e/git-ops.js +35 -2
  38. package/dist/render/constants.d.ts +16 -0
  39. package/dist/render/constants.js +16 -1
  40. package/dist/render/export-spec.d.ts +7 -1
  41. package/dist/render/export-spec.js +51 -5
  42. package/dist/render/index.d.ts +3 -2
  43. package/dist/render/index.js +2 -2
  44. package/dist/render/roadmap-render.js +164 -60
  45. package/dist/render/scope-outlook.d.ts +5 -0
  46. package/dist/render/scope-outlook.js +3 -0
  47. package/dist/render/spec-render.d.ts +28 -2
  48. package/dist/render/spec-render.js +111 -14
  49. package/dist/render/text-utils.d.ts +6 -0
  50. package/dist/render/text-utils.js +23 -0
  51. package/dist/scm/binary.d.ts +3 -0
  52. package/dist/scm/binary.js +10 -2
  53. package/dist/scm/call.d.ts +5 -0
  54. package/dist/scm/call.js +5 -0
  55. package/dist/scm/index.d.ts +1 -0
  56. package/dist/scm/index.js +1 -0
  57. package/dist/scm/main.d.ts +5 -0
  58. package/dist/scm/main.js +27 -0
  59. package/dist/scm/readiness-cli.d.ts +24 -0
  60. package/dist/scm/readiness-cli.js +85 -0
  61. package/dist/scm/readiness.d.ts +104 -0
  62. package/dist/scm/readiness.js +421 -0
  63. package/dist/scope/batch-promote.d.ts +26 -0
  64. package/dist/scope/batch-promote.js +167 -0
  65. package/dist/scope/index.d.ts +1 -0
  66. package/dist/scope/index.js +1 -0
  67. package/dist/scope/main.d.ts +2 -0
  68. package/dist/scope/main.js +58 -7
  69. package/dist/scope/wip-cap-check.d.ts +6 -0
  70. package/dist/scope/wip-cap-check.js +14 -2
  71. package/dist/session/index.d.ts +2 -0
  72. package/dist/session/index.js +2 -0
  73. package/dist/session/process-cost-constants.d.ts +9 -0
  74. package/dist/session/process-cost-constants.js +11 -0
  75. package/dist/session/process-cost.d.ts +53 -0
  76. package/dist/session/process-cost.js +82 -0
  77. package/dist/session/ritual-sentinel.d.ts +5 -0
  78. package/dist/session/ritual-sentinel.js +12 -1
  79. package/dist/session/session-ready.d.ts +67 -0
  80. package/dist/session/session-ready.js +264 -0
  81. package/dist/session/session-start.d.ts +63 -1
  82. package/dist/session/session-start.js +432 -24
  83. package/dist/session/verify-session-ritual.d.ts +8 -0
  84. package/dist/session/verify-session-ritual.js +95 -35
  85. package/dist/tool-events/classify.d.ts +20 -0
  86. package/dist/tool-events/classify.js +634 -0
  87. package/dist/tool-events/index.d.ts +10 -0
  88. package/dist/tool-events/index.js +10 -0
  89. package/dist/tool-events/summarize.d.ts +34 -0
  90. package/dist/tool-events/summarize.js +93 -0
  91. package/dist/tool-events/types.d.ts +52 -0
  92. package/dist/tool-events/types.js +13 -0
  93. package/dist/triage/welcome/index.d.ts +1 -1
  94. package/dist/triage/welcome/index.js +1 -1
  95. package/dist/triage/welcome/onboard.js +7 -1
  96. package/dist/triage/welcome/prior-state.d.ts +7 -0
  97. package/dist/triage/welcome/prior-state.js +16 -2
  98. package/dist/triage/welcome/writers.d.ts +10 -0
  99. package/dist/triage/welcome/writers.js +72 -2
  100. package/package.json +7 -3
@@ -7,7 +7,7 @@ export declare const DEPRECATED_REDIRECT_SENTINEL = "<!-- deft:deprecated-redire
7
7
  export declare const DEPRECATED_SKILL_REDIRECT_SENTINEL = "<!-- deft:deprecated-skill-redirect -->";
8
8
  export declare const REDIRECT_STUB_HEADER_LINES = 8;
9
9
  export declare const TASKFILE_INCLUDE_SNIPPET = "version: '3'\n\nincludes:\n deft:\n taskfile: ./.deft/core/Taskfile.yml\n optional: true\n";
10
- export declare const DOCTOR_ALLOWED_FLAGS: readonly ["--session", "--fix", "--repair", "--repair-taskfile", "--json", "--quiet", "--full", "--network", "--project-root", "-h", "--help"];
10
+ export declare const DOCTOR_ALLOWED_FLAGS: readonly ["--session", "--fix", "--repair", "--repair-taskfile", "--json", "--quiet", "--full", "--network", "--project-root", "--force", "--openclaw-all-agents", "-h", "--help"];
11
11
  /** npm consumer deposit after #2022 Phase 3 -- Python scripts/ tree is intentionally absent. */
12
12
  export declare const NPM_PACKAGE_NAME = "@deftai/directive";
13
13
  export declare const PUBLIC_NPM_REGISTRY = "https://registry.npmjs.org/";
@@ -23,6 +23,8 @@ export const DOCTOR_ALLOWED_FLAGS = [
23
23
  "--full",
24
24
  "--network",
25
25
  "--project-root",
26
+ "--force",
27
+ "--openclaw-all-agents",
26
28
  "-h",
27
29
  "--help",
28
30
  ];
@@ -8,6 +8,8 @@ export function parseDoctorFlags(args) {
8
8
  let network = false;
9
9
  let help = false;
10
10
  let projectRoot = null;
11
+ let force = false;
12
+ let openclawAllAgents = false;
11
13
  const unknown = [];
12
14
  let i = 0;
13
15
  while (i < args.length) {
@@ -30,6 +32,12 @@ export function parseDoctorFlags(args) {
30
32
  else if (token === "--network") {
31
33
  network = true;
32
34
  }
35
+ else if (token === "--force") {
36
+ force = true;
37
+ }
38
+ else if (token === "--openclaw-all-agents") {
39
+ openclawAllAgents = true;
40
+ }
33
41
  else if (token === "-h" || token === "--help") {
34
42
  help = true;
35
43
  }
@@ -56,7 +64,19 @@ export function parseDoctorFlags(args) {
56
64
  }
57
65
  i += 1;
58
66
  }
59
- return { session, fix, json, quiet, full, network, help, projectRoot, unknown };
67
+ return {
68
+ session,
69
+ fix,
70
+ json,
71
+ quiet,
72
+ full,
73
+ network,
74
+ help,
75
+ projectRoot,
76
+ force,
77
+ openclawAllAgents,
78
+ unknown,
79
+ };
60
80
  }
61
81
  export function formatUnknownFlagsError(unknown) {
62
82
  return `Unknown flag(s): ${unknown.join(", ")}`;
@@ -7,6 +7,7 @@ export * from "./json.js";
7
7
  export * from "./main.js";
8
8
  export * from "./manifest.js";
9
9
  export * from "./npm-registry.js";
10
+ export * from "./openclaw-skills.js";
10
11
  export * from "./paths.js";
11
12
  export * from "./payload-staleness.js";
12
13
  export * from "./release-availability.js";
@@ -7,6 +7,7 @@ export * from "./json.js";
7
7
  export * from "./main.js";
8
8
  export * from "./manifest.js";
9
9
  export * from "./npm-registry.js";
10
+ export * from "./openclaw-skills.js";
10
11
  export * from "./paths.js";
11
12
  export * from "./payload-staleness.js";
12
13
  export * from "./release-availability.js";
@@ -21,6 +21,7 @@ import { formatAllowedFlagsHint, formatUnknownFlagsError, parseDoctorFlags } fro
21
21
  import { pythonJsonDump } from "./json.js";
22
22
  import { parseInstallRootFromAgentsMd } from "./manifest.js";
23
23
  import { runNpmRegistryMirrorCheck } from "./npm-registry.js";
24
+ import { runOpenClawSkillPinsCheck } from "./openclaw-skills.js";
24
25
  import { createPlainSink } from "./output.js";
25
26
  import { readTextSafe, resolveFrameworkRootForProject, resolvePath, resolveVersion, runningInsideDeftRepo, } from "./paths.js";
26
27
  import { runPayloadStalenessCheck } from "./payload-staleness.js";
@@ -350,6 +351,27 @@ export function cmdDoctor(args, seams = {}) {
350
351
  if (!jsonMode) {
351
352
  sink.blank();
352
353
  }
354
+ sink.info("Checking OpenClaw always-pin skills...");
355
+ runOpenClawSkillPinsCheck(sink, addFinding, {
356
+ frameworkRoot,
357
+ fixMode,
358
+ jsonMode,
359
+ force: flags.force,
360
+ allAgents: flags.openclawAllAgents,
361
+ seams: {
362
+ ...seams,
363
+ env: seams.openclawEnv,
364
+ homeDir: seams.openclawHomeDir,
365
+ contentRootFor: seams.openclawContentRootFor,
366
+ isDir: seams.isDir,
367
+ isFile: seams.isFile,
368
+ isTty: seams.isTty,
369
+ readYn: seams.readYn,
370
+ },
371
+ });
372
+ if (!jsonMode) {
373
+ sink.blank();
374
+ }
353
375
  sink.info("Checking xBRIEF project envelope version...");
354
376
  runXbriefEnvelopeVersionCheck(projectRoot, sink, addFinding, seams);
355
377
  let resolution = null;
@@ -0,0 +1,143 @@
1
+ /**
2
+ * OpenClaw always-pin skill detect + doctor --fix wire (#3001 / #3008).
3
+ *
4
+ * When OpenClaw signals are present, doctor checks the main workspace skills
5
+ * root for the four always-pin skills (#2508). Missing pins emit a warning with
6
+ * remediation `deft doctor --fix`. Under fixMode, pins are **copied** into the
7
+ * workspace skills root (not symlinked into the npm content package).
8
+ *
9
+ * OpenClaw 2026.7.x rejects workspace skills that resolve outside the configured
10
+ * skills root (`reason=symlink-escape`). A pin that is only a symlink into
11
+ * `@deftai/directive-content` therefore looks "present" on disk while the host
12
+ * never loads it (#3008). Prefer real directory copies; treat escaping
13
+ * symlinks as divergent so `--fix` can replace them.
14
+ *
15
+ * Multi-seat (`workspace-*`) targets only when `--openclaw-all-agents` is set.
16
+ */
17
+ import type { OutputSink } from "./output.js";
18
+ import type { DoctorSeams, Finding } from "./types.js";
19
+ /** Stable doctor check id for JSON findings. */
20
+ export declare const OPENCLAW_SKILL_PINS_CHECK = "openclaw-skill-pins";
21
+ /** Always-pin skill directory names (#2508 / cold-start). */
22
+ export declare const OPENCLAW_ALWAYS_PIN_SKILLS: readonly ["deft-directive-build", "deft-directive-pre-pr", "deft-directive-review-cycle", "deft-directive-swarm"];
23
+ export type OpenClawAlwaysPinSkill = (typeof OPENCLAW_ALWAYS_PIN_SKILLS)[number];
24
+ /** Env keys that count as strong OpenClaw signals (#3001). */
25
+ export declare const OPENCLAW_ENV_SIGNAL_KEYS: readonly ["OPENCLAW", "DEFT_PROBE_OPENCLAW", "DEFT_AGENT_RUNTIME", "OPENCLAW_STATE_DIR"];
26
+ export interface OpenClawSkillPinsSeams {
27
+ readonly env?: NodeJS.ProcessEnv;
28
+ readonly homeDir?: () => string;
29
+ readonly isDir?: (path: string) => boolean;
30
+ readonly isFile?: (path: string) => boolean;
31
+ readonly pathExists?: (path: string) => boolean;
32
+ readonly readDir?: (path: string) => string[];
33
+ readonly lstatKind?: (path: string) => "file" | "dir" | "symlink" | "other" | "missing";
34
+ readonly mkdirp?: (path: string) => void;
35
+ readonly symlinkDir?: (target: string, path: string) => void;
36
+ readonly copyDir?: (src: string, dst: string) => void;
37
+ readonly removePath?: (path: string) => void;
38
+ readonly renamePath?: (from: string, to: string) => void;
39
+ readonly contentRootFor?: (frameworkRoot: string) => string;
40
+ readonly isTty?: () => boolean;
41
+ readonly readYn?: (prompt: string, defaultYes: boolean) => boolean;
42
+ }
43
+ export interface OpenClawPinAssessment {
44
+ readonly skillsDir: string;
45
+ readonly present: readonly OpenClawAlwaysPinSkill[];
46
+ readonly missing: readonly OpenClawAlwaysPinSkill[];
47
+ readonly divergent: readonly OpenClawAlwaysPinSkill[];
48
+ }
49
+ export interface OpenClawDetectResult {
50
+ readonly detected: boolean;
51
+ readonly reasons: readonly string[];
52
+ readonly stateDir: string;
53
+ readonly mainSkillsDir: string;
54
+ }
55
+ export type PinInstallMethod = "symlink" | "copy" | "skipped" | "already-present";
56
+ export interface PinInstallResult {
57
+ readonly skillId: OpenClawAlwaysPinSkill;
58
+ readonly method: PinInstallMethod;
59
+ readonly target: string;
60
+ readonly source: string;
61
+ readonly detail?: string;
62
+ }
63
+ /**
64
+ * Resolve OpenClaw state directory: OPENCLAW_STATE_DIR or ~/.openclaw.
65
+ */
66
+ export declare function resolveOpenClawStateDir(env?: NodeJS.ProcessEnv, home?: string): string;
67
+ /**
68
+ * Main agent workspace skills root under the state dir.
69
+ */
70
+ export declare function resolveMainSkillsDir(stateDir: string): string;
71
+ /**
72
+ * Detect OpenClaw from env signals and/or presence of the state directory.
73
+ */
74
+ export declare function detectOpenClaw(env?: NodeJS.ProcessEnv, options?: {
75
+ homeDir?: string;
76
+ isDir?: (path: string) => boolean;
77
+ }): OpenClawDetectResult;
78
+ /**
79
+ * List in-scope skills directories. Default: main only.
80
+ * With allAgents: main + every workspace- star /skills under the state dir.
81
+ */
82
+ export declare function listInScopeSkillsDirs(stateDir: string, allAgents: boolean, seams?: Pick<OpenClawSkillPinsSeams, "isDir" | "readDir">): string[];
83
+ /**
84
+ * Resolve content package skills/<id> for a pin.
85
+ */
86
+ export declare function resolvePinSourceDir(contentBase: string, skillId: string): string;
87
+ /**
88
+ * True when `path` is a symlink whose resolved real path is outside `skillsDir`
89
+ * (OpenClaw `symlink-escape` / #3008).
90
+ */
91
+ export declare function isEscapingSkillSymlink(skillsDir: string, path: string, seams?: Pick<OpenClawSkillPinsSeams, "lstatKind">): boolean;
92
+ /**
93
+ * Assess which always-pins are present / missing / divergent in a skills root.
94
+ *
95
+ * - present: real directory (or non-escaping symlink) with SKILL.md matching
96
+ * the content package when `contentBase` is supplied
97
+ * - missing: path does not exist
98
+ * - divergent: path exists but is not a usable OpenClaw pin (file, empty dir,
99
+ * broken link, **escaping symlink**, or **stale SKILL.md** vs package — #3008)
100
+ */
101
+ export declare function assessOpenClawPins(skillsDir: string, seams?: Pick<OpenClawSkillPinsSeams, "isDir" | "isFile" | "pathExists" | "lstatKind">, options?: {
102
+ contentBase?: string;
103
+ }): OpenClawPinAssessment;
104
+ /**
105
+ * Install one pin into a skills root.
106
+ *
107
+ * Default: **copy** into the workspace skills root (#3008). OpenClaw rejects
108
+ * skills that resolve outside the workspace skills root via symlink-escape, so
109
+ * symlinking into the npm content package leaves pins unloaded while doctor
110
+ * reports "present". Opt into legacy symlink-first with `preferSymlink: true`
111
+ * (still falls back to copy). Never deletes unrelated user skills. Divergent
112
+ * targets (including escaping symlinks) require force or TTY confirm.
113
+ *
114
+ * Stale copies (SKILL.md differs from package) are not "already-present" —
115
+ * doctor --fix refreshes them so upgrades land without manual delete (#3008 P1).
116
+ * Forced replace stages into a sibling temp dir first so a failed copy does not
117
+ * leave the pin permanently deleted (#3008 P1).
118
+ */
119
+ export declare function installOpenClawPin(skillId: OpenClawAlwaysPinSkill, sourceDir: string, skillsDir: string, options?: {
120
+ force?: boolean;
121
+ allowOverwrite?: boolean;
122
+ /** When true, try symlink first (legacy #3001). Default false — copy (#3008). */
123
+ preferSymlink?: boolean;
124
+ /**
125
+ * When true, refresh copied pins whose SKILL.md no longer matches the
126
+ * package (package upgrade path). Doctor --fix sets this.
127
+ */
128
+ refreshStale?: boolean;
129
+ }, seams?: OpenClawSkillPinsSeams): PinInstallResult;
130
+ export interface RunOpenClawSkillPinsOptions {
131
+ readonly frameworkRoot: string;
132
+ readonly fixMode: boolean;
133
+ readonly jsonMode: boolean;
134
+ readonly force: boolean;
135
+ readonly allAgents: boolean;
136
+ readonly seams?: DoctorSeams & OpenClawSkillPinsSeams;
137
+ }
138
+ /**
139
+ * Doctor check: detect OpenClaw + missing always-pins; optionally fix.
140
+ * No-ops when OpenClaw signals are absent.
141
+ */
142
+ export declare function runOpenClawSkillPinsCheck(sink: OutputSink, addFinding: (finding: Finding) => void, options: RunOpenClawSkillPinsOptions): void;
143
+ //# sourceMappingURL=openclaw-skills.d.ts.map