@deftai/directive-core 0.92.0 → 0.93.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 (52) hide show
  1. package/dist/doctor/index.d.ts +1 -0
  2. package/dist/doctor/index.js +1 -0
  3. package/dist/doctor/main.js +12 -0
  4. package/dist/doctor/openclaw-l2-adapter.d.ts +26 -0
  5. package/dist/doctor/openclaw-l2-adapter.js +199 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +2 -0
  8. package/dist/init-deposit/hygiene.js +22 -0
  9. package/dist/init-deposit/index.d.ts +3 -0
  10. package/dist/init-deposit/index.js +3 -0
  11. package/dist/init-deposit/init-deposit.js +10 -0
  12. package/dist/init-deposit/refresh.js +11 -0
  13. package/dist/init-deposit/scaffold.js +3 -133
  14. package/dist/init-deposit/skill-discovery-deposit.d.ts +65 -0
  15. package/dist/init-deposit/skill-discovery-deposit.js +287 -0
  16. package/dist/init-deposit/skill-discovery-hosts.d.ts +94 -0
  17. package/dist/init-deposit/skill-discovery-hosts.js +217 -0
  18. package/dist/init-deposit/slash-deposit.d.ts +46 -0
  19. package/dist/init-deposit/slash-deposit.js +174 -0
  20. package/dist/policy/host-slash-commands.d.ts +28 -0
  21. package/dist/policy/host-slash-commands.js +103 -0
  22. package/dist/policy/index.d.ts +1 -0
  23. package/dist/policy/index.js +47 -7
  24. package/dist/slash/emitters.d.ts +102 -0
  25. package/dist/slash/emitters.js +148 -0
  26. package/dist/slash/generator.d.ts +98 -0
  27. package/dist/slash/generator.js +145 -0
  28. package/dist/slash/index.d.ts +16 -0
  29. package/dist/slash/index.js +16 -0
  30. package/dist/slash/openclaw-adapter.d.ts +64 -0
  31. package/dist/slash/openclaw-adapter.js +198 -0
  32. package/dist/slash/openclaw-deposit.d.ts +73 -0
  33. package/dist/slash/openclaw-deposit.js +279 -0
  34. package/dist/slash/openclaw-slugs.d.ts +52 -0
  35. package/dist/slash/openclaw-slugs.js +126 -0
  36. package/dist/slash/product-set.d.ts +50 -0
  37. package/dist/slash/product-set.js +142 -0
  38. package/dist/vbrief-validate/plan-hooks.d.ts +4 -0
  39. package/dist/vbrief-validate/plan-hooks.js +50 -0
  40. package/dist/xbrief/create.d.ts +36 -0
  41. package/dist/xbrief/create.js +285 -0
  42. package/dist/xbrief/index.d.ts +14 -0
  43. package/dist/xbrief/index.js +42 -0
  44. package/dist/xbrief/paths.d.ts +37 -0
  45. package/dist/xbrief/paths.js +123 -0
  46. package/dist/xbrief/styles.d.ts +36 -0
  47. package/dist/xbrief/styles.js +235 -0
  48. package/dist/xbrief/types.d.ts +50 -0
  49. package/dist/xbrief/types.js +17 -0
  50. package/dist/xbrief/verify.d.ts +30 -0
  51. package/dist/xbrief/verify.js +251 -0
  52. package/package.json +11 -3
@@ -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-l2-adapter.js";
10
11
  export * from "./openclaw-skills.js";
11
12
  export * from "./paths.js";
12
13
  export * from "./payload-staleness.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-l2-adapter.js";
10
11
  export * from "./openclaw-skills.js";
11
12
  export * from "./paths.js";
12
13
  export * from "./payload-staleness.js";
@@ -22,6 +22,7 @@ import { formatAllowedFlagsHint, formatUnknownFlagsError, parseDoctorFlags } fro
22
22
  import { pythonJsonDump } from "./json.js";
23
23
  import { parseInstallRootFromAgentsMd } from "./manifest.js";
24
24
  import { runNpmRegistryMirrorCheck } from "./npm-registry.js";
25
+ import { runOpenClawL2AdapterCheck } from "./openclaw-l2-adapter.js";
25
26
  import { runOpenClawSkillPinsCheck } from "./openclaw-skills.js";
26
27
  import { createPlainSink } from "./output.js";
27
28
  import { readTextSafe, resolveFrameworkRootForProject, resolvePath, resolveVersion, runningInsideDeftRepo, } from "./paths.js";
@@ -409,6 +410,17 @@ export function cmdDoctor(args, seams = {}) {
409
410
  if (!jsonMode) {
410
411
  sink.blank();
411
412
  }
413
+ sink.info("Checking OpenClaw L2 product-command skills...");
414
+ runOpenClawL2AdapterCheck(sink, addFinding, {
415
+ projectRoot,
416
+ fixMode,
417
+ jsonMode,
418
+ allAgents: flags.openclawAllAgents,
419
+ seams,
420
+ });
421
+ if (!jsonMode) {
422
+ sink.blank();
423
+ }
412
424
  sink.info("Checking xBRIEF project envelope version...");
413
425
  runXbriefEnvelopeVersionCheck(projectRoot, sink, addFinding, seams);
414
426
  let resolution = null;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Doctor check + --fix wire for OpenClaw L2 product-command skills (#3064 D5).
3
+ *
4
+ * Primary operator recovery path when OpenClaw is detected. Deposits thin
5
+ * user-invocable router + 13 product skills into workspace skills roots.
6
+ * Fail-closed when OC signals are absent. Policy opt-out:
7
+ * `plan.policy.openClawProductCommands: false`.
8
+ */
9
+ import { type OpenClawL2DepositResult } from "../slash/openclaw-deposit.js";
10
+ import type { OutputSink } from "./output.js";
11
+ import type { DoctorSeams, Finding } from "./types.js";
12
+ /** Stable doctor check id for JSON findings. */
13
+ export declare const OPENCLAW_L2_ADAPTER_CHECK = "openclaw-l2-product-commands";
14
+ export interface RunOpenClawL2AdapterOptions {
15
+ readonly projectRoot: string;
16
+ readonly fixMode: boolean;
17
+ readonly jsonMode: boolean;
18
+ readonly allAgents: boolean;
19
+ readonly seams?: DoctorSeams;
20
+ }
21
+ /**
22
+ * Doctor check: OpenClaw L2 product-command skills present and current.
23
+ * No-ops when OpenClaw is not detected. Fix mode deposits managed skills.
24
+ */
25
+ export declare function runOpenClawL2AdapterCheck(sink: OutputSink, addFinding: (finding: Finding) => void, options: RunOpenClawL2AdapterOptions): OpenClawL2DepositResult | null;
26
+ //# sourceMappingURL=openclaw-l2-adapter.d.ts.map
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Doctor check + --fix wire for OpenClaw L2 product-command skills (#3064 D5).
3
+ *
4
+ * Primary operator recovery path when OpenClaw is detected. Deposits thin
5
+ * user-invocable router + 13 product skills into workspace skills roots.
6
+ * Fail-closed when OC signals are absent. Policy opt-out:
7
+ * `plan.policy.openClawProductCommands: false`.
8
+ */
9
+ import { existsSync, readFileSync, statSync } from "node:fs";
10
+ import { homedir } from "node:os";
11
+ import { join } from "node:path";
12
+ import { generateOpenClawSkillArtifacts, isManagedOpenClawL2Skill, listOpenClawManagedSkillSlugs, } from "../slash/openclaw-adapter.js";
13
+ import { depositOpenClawL2ProductCommands, loadOpenClawProductCommandsPolicyFromProject, } from "../slash/openclaw-deposit.js";
14
+ import { detectOpenClaw, listInScopeSkillsDirs } from "./openclaw-skills.js";
15
+ /** Stable doctor check id for JSON findings. */
16
+ export const OPENCLAW_L2_ADAPTER_CHECK = "openclaw-l2-product-commands";
17
+ const DOC_OPENCLAW_HOST = "docs/openclaw-agent-host.md";
18
+ const DOC_SLASH_MULTI = "docs/slash-multi-host.md";
19
+ const REMEDIATION_FIX = "deft doctor --fix";
20
+ function defaultIsDir(path) {
21
+ try {
22
+ return statSync(path).isDirectory();
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ }
28
+ function assessGaps(skillsDirs) {
29
+ const artifacts = generateOpenClawSkillArtifacts();
30
+ const missing = [];
31
+ const stale = [];
32
+ let present = 0;
33
+ for (const skillsDir of skillsDirs) {
34
+ for (const art of artifacts) {
35
+ const path = join(skillsDir, art.slug, "SKILL.md");
36
+ if (!existsSync(path)) {
37
+ missing.push(`${skillsDir}/${art.slug}`);
38
+ continue;
39
+ }
40
+ let raw;
41
+ try {
42
+ raw = readFileSync(path, "utf8");
43
+ }
44
+ catch {
45
+ missing.push(`${skillsDir}/${art.slug}`);
46
+ continue;
47
+ }
48
+ if (!isManagedOpenClawL2Skill(raw)) {
49
+ // Consumer customization — not a gap for doctor (preserve).
50
+ present += 1;
51
+ continue;
52
+ }
53
+ if (raw === art.skillMarkdown) {
54
+ present += 1;
55
+ }
56
+ else {
57
+ stale.push(`${skillsDir}/${art.slug}`);
58
+ }
59
+ }
60
+ }
61
+ return { missing, stale, present };
62
+ }
63
+ /**
64
+ * Doctor check: OpenClaw L2 product-command skills present and current.
65
+ * No-ops when OpenClaw is not detected. Fix mode deposits managed skills.
66
+ */
67
+ export function runOpenClawL2AdapterCheck(sink, addFinding, options) {
68
+ const seams = options.seams ?? {};
69
+ const env = seams.openclawEnv ?? process.env;
70
+ const homeDirFn = seams.openclawHomeDir ?? (() => homedir());
71
+ const isDir = seams.isDir ?? defaultIsDir;
72
+ const home = homeDirFn();
73
+ const detect = detectOpenClaw(env, { homeDir: home, isDir });
74
+ if (!detect.detected) {
75
+ sink.info(`${OPENCLAW_L2_ADAPTER_CHECK}: skip -- OpenClaw not detected`);
76
+ addFinding({
77
+ severity: "skip",
78
+ message: "OpenClaw not detected",
79
+ check: OPENCLAW_L2_ADAPTER_CHECK,
80
+ status: "skip",
81
+ reason: "openclaw-not-detected",
82
+ });
83
+ return null;
84
+ }
85
+ const policy = loadOpenClawProductCommandsPolicyFromProject(options.projectRoot);
86
+ if (!policy) {
87
+ // Opt-out: under --fix, strip managed L2 skills so the adapter does not
88
+ // stay active after openClawProductCommands=false (#3064 Greptile P1).
89
+ let depositResult = null;
90
+ if (options.fixMode) {
91
+ depositResult = depositOpenClawL2ProductCommands({
92
+ projectRoot: options.projectRoot,
93
+ env,
94
+ homeDir: home,
95
+ allAgents: options.allAgents,
96
+ policy: false,
97
+ printf: (t) => {
98
+ if (!options.jsonMode)
99
+ sink.info(t.trimEnd());
100
+ },
101
+ isDir,
102
+ });
103
+ const message = `${OPENCLAW_L2_ADAPTER_CHECK}: opted out (plan.policy.openClawProductCommands=false); ` +
104
+ (depositResult.removedPaths.length > 0
105
+ ? `removed ${depositResult.removedPaths.length} managed skill path(s)`
106
+ : "no managed L2 skills to remove");
107
+ sink.success(message);
108
+ addFinding({
109
+ severity: "skip",
110
+ message,
111
+ check: OPENCLAW_L2_ADAPTER_CHECK,
112
+ status: "opted-out-fixed",
113
+ reason: "policy-false",
114
+ removed: depositResult.removedPaths,
115
+ detect_reasons: detect.reasons,
116
+ });
117
+ return depositResult;
118
+ }
119
+ sink.info(`${OPENCLAW_L2_ADAPTER_CHECK}: skip -- plan.policy.openClawProductCommands=false`);
120
+ addFinding({
121
+ severity: "skip",
122
+ message: "OpenClaw L2 product commands opted out via policy; run `deft doctor --fix` to remove managed skills",
123
+ check: OPENCLAW_L2_ADAPTER_CHECK,
124
+ status: "opted-out",
125
+ reason: "policy-false",
126
+ });
127
+ return null;
128
+ }
129
+ const skillsDirs = listInScopeSkillsDirs(detect.stateDir, options.allAgents, {
130
+ isDir,
131
+ });
132
+ const gaps = assessGaps(skillsDirs);
133
+ const expectedCount = listOpenClawManagedSkillSlugs().length * skillsDirs.length;
134
+ if (gaps.missing.length === 0 && gaps.stale.length === 0) {
135
+ const message = `${OPENCLAW_L2_ADAPTER_CHECK}: OpenClaw L2 product-command skills present ` +
136
+ `(router + 13) in ${options.allAgents ? "main + workspace-* seats" : "main workspace"}`;
137
+ sink.success(message);
138
+ addFinding({
139
+ severity: "skip",
140
+ message,
141
+ check: OPENCLAW_L2_ADAPTER_CHECK,
142
+ status: "present",
143
+ skills_dirs: skillsDirs,
144
+ expected: expectedCount,
145
+ present: gaps.present,
146
+ detect_reasons: detect.reasons,
147
+ });
148
+ return null;
149
+ }
150
+ let depositResult = null;
151
+ if (options.fixMode) {
152
+ depositResult = depositOpenClawL2ProductCommands({
153
+ projectRoot: options.projectRoot,
154
+ env,
155
+ homeDir: home,
156
+ allAgents: options.allAgents,
157
+ policy: true,
158
+ printf: (t) => {
159
+ if (!options.jsonMode)
160
+ sink.info(t.trimEnd());
161
+ },
162
+ isDir,
163
+ });
164
+ const post = assessGaps(skillsDirs);
165
+ if (post.missing.length === 0 && post.stale.length === 0) {
166
+ const message = `${OPENCLAW_L2_ADAPTER_CHECK}: deposited OpenClaw L2 product-command skills; ` +
167
+ "restart the OpenClaw gateway or start a new session so available_skills refreshes";
168
+ sink.success(message);
169
+ addFinding({
170
+ severity: "skip",
171
+ message,
172
+ check: OPENCLAW_L2_ADAPTER_CHECK,
173
+ status: "fixed",
174
+ skills_dirs: skillsDirs,
175
+ written: depositResult.writtenPaths,
176
+ detect_reasons: detect.reasons,
177
+ });
178
+ return depositResult;
179
+ }
180
+ }
181
+ const message = `${OPENCLAW_L2_ADAPTER_CHECK}: OpenClaw L2 product-command skills incomplete ` +
182
+ `(missing: ${gaps.missing.length}, stale: ${gaps.stale.length}) under ${skillsDirs.join(", ")}. ` +
183
+ `Remediation: ${REMEDIATION_FIX}. See ${DOC_OPENCLAW_HOST}, ${DOC_SLASH_MULTI}.`;
184
+ sink.warn(message);
185
+ addFinding({
186
+ severity: "warning",
187
+ message,
188
+ check: OPENCLAW_L2_ADAPTER_CHECK,
189
+ status: "missing",
190
+ missing: gaps.missing,
191
+ stale: gaps.stale,
192
+ skills_dirs: skillsDirs,
193
+ suggestion: REMEDIATION_FIX,
194
+ docs: [DOC_OPENCLAW_HOST, DOC_SLASH_MULTI],
195
+ detect_reasons: detect.reasons,
196
+ });
197
+ return depositResult;
198
+ }
199
+ //# sourceMappingURL=openclaw-l2-adapter.js.map
package/dist/index.d.ts CHANGED
@@ -50,6 +50,7 @@ export * as resolution from "./resolution/index.js";
50
50
  export * as scm from "./scm/index.js";
51
51
  export * as scope from "./scope/index.js";
52
52
  export * as session from "./session/index.js";
53
+ export * as slash from "./slash/index.js";
53
54
  export * as slice from "./slice/index.js";
54
55
  export * as storyReady from "./story-ready/index.js";
55
56
  export * as swarm from "./swarm/index.js";
@@ -65,6 +66,7 @@ export * as vbriefValidation from "./vbrief-validation/index.js";
65
66
  export * as verifyEnv from "./verify-env/index.js";
66
67
  export * as verifySource from "./verify-source/index.js";
67
68
  export * as wipCap from "./wip-cap/index.js";
69
+ export * as xbrief from "./xbrief/index.js";
68
70
  export * as xbriefMigrate from "./xbrief-migrate/index.js";
69
71
  export declare const CORE_PACKAGE: "@deftai/directive-core";
70
72
  /** Returns identifying metadata for the core engine package. */
package/dist/index.js CHANGED
@@ -51,6 +51,7 @@ export * as resolution from "./resolution/index.js";
51
51
  export * as scm from "./scm/index.js";
52
52
  export * as scope from "./scope/index.js";
53
53
  export * as session from "./session/index.js";
54
+ export * as slash from "./slash/index.js";
54
55
  export * as slice from "./slice/index.js";
55
56
  export * as storyReady from "./story-ready/index.js";
56
57
  export * as swarm from "./swarm/index.js";
@@ -66,6 +67,7 @@ export * as vbriefValidation from "./vbrief-validation/index.js";
66
67
  export * as verifyEnv from "./verify-env/index.js";
67
68
  export * as verifySource from "./verify-source/index.js";
68
69
  export * as wipCap from "./wip-cap/index.js";
70
+ export * as xbrief from "./xbrief/index.js";
69
71
  export * as xbriefMigrate from "./xbrief-migrate/index.js";
70
72
  export const CORE_PACKAGE = "@deftai/directive-core";
71
73
  /** Returns identifying metadata for the core engine package. */
@@ -16,6 +16,9 @@ import { readdir, rm, stat } from "node:fs/promises";
16
16
  import { dirname, join, relative } from "node:path";
17
17
  import { gitPorcelain } from "../story-ready/git.js";
18
18
  import { CANONICAL_INSTALL_ROOT } from "./constants.js";
19
+ import { CONSUMER_SKILL_DISCOVERY_INVENTORY } from "./skill-discovery-deposit.js";
20
+ import { hostSkillRelativePath, listSkillDiscoveryHosts } from "./skill-discovery-hosts.js";
21
+ import { slashCommandManagedExactPaths } from "./slash-deposit.js";
19
22
  export const CODEQL_CONFIG_REL = ".github/codeql/codeql-config.yml";
20
23
  export const CORE_GUARD_WORKFLOW_REL = ".github/workflows/deft-core-guard.yml";
21
24
  // The lifecycle dir names are identical across the legacy `vbrief/` tree and the
@@ -41,16 +44,35 @@ export const CONSUMER_GUARD_MUST_FIRE = [
41
44
  "xbrief/proposed/example-scope.xbrief.json",
42
45
  "vbrief/pending/example-scope.vbrief.json",
43
46
  ];
47
+ /** Exact managed multi-host skill pointer paths only (#75 Greptile P1). */
48
+ function multiHostSkillDiscoveryManagedMatchers() {
49
+ // Exact SKILL.md paths only so consumer-authored siblings under the same
50
+ // host skills tree stay app-owned (not staged / not guard-exempt).
51
+ const matchers = [];
52
+ for (const host of listSkillDiscoveryHosts()) {
53
+ for (const skill of CONSUMER_SKILL_DISCOVERY_INVENTORY) {
54
+ matchers.push({ exact: hostSkillRelativePath(host, skill.dir) });
55
+ }
56
+ }
57
+ return matchers;
58
+ }
44
59
  /** Single source of truth for installer-managed paths (#1440 / #1576). */
45
60
  export function installerManagedMatchers() {
46
61
  return [
47
62
  { exact: "AGENTS.md" },
48
63
  { prefix: ".agents/" },
64
+ // Multi-host skill discovery thin pointers (#75 residual) — not slash commands (#55).
65
+ // Exact inventory paths only; never claim the whole host skills tree.
66
+ ...multiHostSkillDiscoveryManagedMatchers(),
49
67
  { prefix: ".githooks/" },
50
68
  { exact: ".claude/settings.json" },
51
69
  { exact: ".grok/hooks/deft.json" },
52
70
  { exact: ".cursor/hooks.json" },
53
71
  { exact: ".codex/hooks.json" },
72
+ // Multi-host slash product files only (#3054 / L8 prefer commit).
73
+ // Exact paths — not directory prefixes — so consumer custom commands under
74
+ // the same host dirs stay app-owned for staging + no-mixed-core-and-app.
75
+ ...slashCommandManagedExactPaths().map((exact) => ({ exact })),
54
76
  { exact: ".gitattributes" },
55
77
  { exact: ".gitignore" },
56
78
  // Installer-deposited Prettier gate exclusion (#2534); must be allowlisted or
@@ -6,5 +6,8 @@ export * from "./legacy-detect.js";
6
6
  export * from "./migrate.js";
7
7
  export * from "./refresh.js";
8
8
  export * from "./scaffold.js";
9
+ export * from "./skill-discovery-deposit.js";
10
+ export * from "./skill-discovery-hosts.js";
11
+ export * from "./slash-deposit.js";
9
12
  export * from "./untrack-core.js";
10
13
  //# sourceMappingURL=index.d.ts.map
@@ -6,5 +6,8 @@ export * from "./legacy-detect.js";
6
6
  export * from "./migrate.js";
7
7
  export * from "./refresh.js";
8
8
  export * from "./scaffold.js";
9
+ export * from "./skill-discovery-deposit.js";
10
+ export * from "./skill-discovery-hosts.js";
11
+ export * from "./slash-deposit.js";
9
12
  export * from "./untrack-core.js";
10
13
  //# sourceMappingURL=index.js.map
@@ -14,6 +14,7 @@ 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
16
  import { renderProjectDefinition } from "../render/project-render.js";
17
+ import { depositOpenClawL2ProductCommands } from "../slash/openclaw-deposit.js";
17
18
  import { removeStaleMigratedFrameworkNarrative } from "../xbrief-migrate/migrate-project.js";
18
19
  import { writeAgentHookDeposit } from "./agent-hooks.js";
19
20
  import { ensureInitGitignoreLines, reconstituteDepositFromContent } from "./gitignore.js";
@@ -22,6 +23,8 @@ import { buildLegacyRefusalJson, buildLegacyRefusalMessage, detectLegacyLayout,
22
23
  import { printMigrateNudgeIfNeeded } from "./migrate.js";
23
24
  import { ensurePrettierIgnoreLines } from "./prettierignore.js";
24
25
  import { CANONICAL_INSTALL_ROOT, depositNeutralization, ensureTaskfile, writeAgentsMd, writeAgentsSkills, writeConsumerGitHooks, writeConsumerVbrief, writeInstallManifest, } from "./scaffold.js";
26
+ import { writeMultiHostSkillDiscovery } from "./skill-discovery-deposit.js";
27
+ import { writeSlashCommandDeposit } from "./slash-deposit.js";
25
28
  import { syncBareVersionMarker } from "./xbrief-projections.js";
26
29
  export function parseInitArgv(canonicalArgv, userArgv = []) {
27
30
  const args = [...canonicalArgv, ...userArgv];
@@ -181,6 +184,7 @@ export async function runInitDeposit(args, io, seams = {}) {
181
184
  writeInstallManifest(projectDir, deftDir, manifestFields);
182
185
  writeAgentsMd(projectDir, deftDir, io);
183
186
  const skillsCreated = writeAgentsSkills(projectDir, io);
187
+ writeMultiHostSkillDiscovery(projectDir, io);
184
188
  await depositNeutralization(projectDir, io);
185
189
  await writeConsumerVbrief(projectDir, deftDir, io);
186
190
  seedMinimalProjectDefinition(projectDir, io);
@@ -191,6 +195,12 @@ export async function runInitDeposit(args, io, seams = {}) {
191
195
  removeStaleMigratedFrameworkNarrative(projectDir);
192
196
  writeConsumerGitHooks(projectDir, deftDir, io, seams.gitHooks);
193
197
  writeAgentHookDeposit(projectDir, io);
198
+ writeSlashCommandDeposit(projectDir, io);
199
+ // #3064: OpenClaw L2 product-command skills when OC signals present (fail-closed otherwise).
200
+ depositOpenClawL2ProductCommands({
201
+ projectRoot: projectDir,
202
+ printf: (t) => io.printf(t),
203
+ });
194
204
  let taskfileWired = false;
195
205
  if (args.nonInteractive) {
196
206
  taskfileWired = ensureTaskfile(projectDir, io);
@@ -21,6 +21,7 @@ import { resolveLifecycleRoot } from "../layout/resolve.js";
21
21
  import { detectNoDeftDirective, NO_DEFT_DIRECTIVE_DISABLED_MESSAGE, NO_DEFT_DIRECTIVE_FLAG_NAME, NO_DEFT_DIRECTIVE_INCONSISTENT_MESSAGE, NO_DEFT_DIRECTIVE_INCONSISTENT_POLICY, } from "../policy/no-deft-directive.js";
22
22
  import { runOrgForceOnMigration } from "../policy/org-force-on-migration.js";
23
23
  import { checkLocalEngineIntegrity, classify, ENGINE_PACKAGE, plan, renderGlobalInstall, resolveEngine, } from "../resolution/index.js";
24
+ import { depositOpenClawL2ProductCommands } from "../slash/openclaw-deposit.js";
24
25
  import { gitPorcelain } from "../story-ready/git.js";
25
26
  import { removeStaleMigratedFrameworkNarrative } from "../xbrief-migrate/migrate-project.js";
26
27
  import { writeAgentHookDeposit } from "./agent-hooks.js";
@@ -31,6 +32,8 @@ import { buildLegacyRefusalJson, buildLegacyRefusalMessage, detectLegacyLayout,
31
32
  import { printMigrateNudgeIfNeeded } from "./migrate.js";
32
33
  import { ensurePrettierIgnoreLines } from "./prettierignore.js";
33
34
  import { CANONICAL_INSTALL_ROOT, depositNeutralization, ensureTaskfile, writeAgentsMd, writeConsumerGitHooks, writeInstallManifest, } from "./scaffold.js";
35
+ import { writeMultiHostSkillDiscovery } from "./skill-discovery-deposit.js";
36
+ import { writeSlashCommandDeposit } from "./slash-deposit.js";
34
37
  import { syncBareVersionMarker, syncConsumerXbriefSchemas, syncExistingBareVersionMarker, } from "./xbrief-projections.js";
35
38
  function hasCanonicalXbriefLifecycle(projectDir) {
36
39
  try {
@@ -464,6 +467,14 @@ export async function runRefreshDeposit(args, io, seams = {}) {
464
467
  }
465
468
  const agentsMdUpdated = writeAgentsMd(projectDir, deftDir, io);
466
469
  writeAgentHookDeposit(projectDir, io);
470
+ // #75 residual: multi-host thin skill discovery (mirror `.agents/skills` inventory).
471
+ writeMultiHostSkillDiscovery(projectDir, io);
472
+ writeSlashCommandDeposit(projectDir, io);
473
+ // #3064: OpenClaw L2 product-command skills when OC signals present (fail-closed otherwise).
474
+ depositOpenClawL2ProductCommands({
475
+ projectRoot: projectDir,
476
+ printf: (t) => io.printf(t),
477
+ });
467
478
  // #2530: root `.githooks/` is a consumer derivative like #2595 marker/schemas —
468
479
  // repair on every refresh, including the already-current no-op path.
469
480
  writeConsumerGitHooks(projectDir, deftDir, io, seams.gitHooks);
@@ -15,6 +15,7 @@ import { agentsRefreshPlan } from "../platform/agents-md.js";
15
15
  import { MIGRATED_ARTIFACT_DIR } from "../xbrief-migrate/constants.js";
16
16
  import { CANONICAL_INSTALL_ROOT } from "./constants.js";
17
17
  import { assertInstallerAllowlistHonors1430, installerManagedGuardEre } from "./hygiene.js";
18
+ import { writeAgentsSkillsFromInventory } from "./skill-discovery-deposit.js";
18
19
  import { syncConsumerXbriefSchemas } from "./xbrief-projections.js";
19
20
  export { CANONICAL_INSTALL_ROOT };
20
21
  export const CORE_GLOB = ".deft/core/**";
@@ -90,125 +91,6 @@ const DEFT_INCLUDE_CHILD_BLOCK = " # Added by deft-install --yes (Epic-4)\n" +
90
91
  " deft:\n" +
91
92
  " taskfile: ./.deft/core/Taskfile.yml\n" +
92
93
  " optional: true\n";
93
- const AGENTS_SKILLS = [
94
- {
95
- dir: "deft",
96
- content: `---
97
- name: deft
98
- description: Apply deft framework standards for AI-assisted development. Use when starting projects, writing code, running tests, making commits, or when the user references deft, project standards, or coding guidelines.
99
- ---
100
-
101
- Read and follow: .deft/core/SKILL.md
102
- `,
103
- },
104
- {
105
- dir: "deft-directive-setup",
106
- content: `---
107
- name: deft-directive-setup
108
- description: >-
109
- Set up a new project with Deft framework standards. Use when the user wants
110
- to bootstrap user preferences, configure a project, or generate a project
111
- specification. Walks through setup conversationally — no separate CLI needed.
112
- ---
113
-
114
- Read and follow: .deft/core/skills/deft-directive-setup/SKILL.md
115
- `,
116
- },
117
- {
118
- dir: "deft-directive-build",
119
- content: `---
120
- name: deft-directive-build
121
- description: >-
122
- Build a project from scope vBRIEFs following Deft framework standards.
123
- Use after deft-directive-setup has generated the project definition, or when
124
- the user has scope vBRIEFs ready to implement. Handles scaffolding,
125
- implementation, testing, and quality checks phase by phase.
126
- ---
127
-
128
- Read and follow: .deft/core/skills/deft-directive-build/SKILL.md
129
- `,
130
- },
131
- {
132
- dir: "deft-directive-review-cycle",
133
- content: `---
134
- name: deft-directive-review-cycle
135
- description: >-
136
- Greptile bot reviewer response workflow. Use when running a review cycle
137
- on a PR — to audit process prerequisites, fetch bot findings, fix all
138
- issues in a single batch commit, and exit cleanly when no P0/P1 issues
139
- remain. Enables cloud agents to run autonomous PR review cycles.
140
- ---
141
-
142
- Read and follow: .deft/core/skills/deft-directive-review-cycle/SKILL.md
143
- `,
144
- },
145
- {
146
- dir: "deft-directive-refinement",
147
- content: `---
148
- name: deft-directive-refinement
149
- description: >-
150
- Structured refinement workflow. Compares open GitHub issues against
151
- the roadmap, triages new issues one-at-a-time with human review, and updates
152
- the roadmap with phase placement, analysis comments, and index entries.
153
- ---
154
-
155
- Read and follow: .deft/core/skills/deft-directive-refinement/SKILL.md
156
- `,
157
- },
158
- {
159
- dir: "deft-directive-swarm",
160
- content: `---
161
- name: deft-directive-swarm
162
- description: >-
163
- Parallel local agent orchestration. Use when running multiple agents
164
- on roadmap items simultaneously — to select non-overlapping tasks, set up
165
- isolated worktrees, launch agents with proven prompts, monitor progress,
166
- handle stalled review cycles, and close out PRs cleanly.
167
- ---
168
-
169
- Read and follow: .deft/core/skills/deft-directive-swarm/SKILL.md
170
- `,
171
- },
172
- {
173
- dir: "deft-directive-interview",
174
- content: `---
175
- name: deft-directive-interview
176
- description: >-
177
- Deterministic structured Q&A interview skill. Use when a skill or workflow
178
- needs to collect structured answers from the user — one question per turn,
179
- numbered options, default acceptance, and a confirmation gate.
180
- ---
181
-
182
- Read and follow: .deft/core/skills/deft-directive-interview/SKILL.md
183
- `,
184
- },
185
- {
186
- dir: "deft-directive-pre-pr",
187
- content: `---
188
- name: deft-directive-pre-pr
189
- description: >-
190
- Iterative pre-PR quality loop (Read-Write-Lint-Diff-Loop). Use before
191
- pushing a branch for PR creation — structured self-review that agents run
192
- to catch issues before they reach the bot reviewer.
193
- ---
194
-
195
- Read and follow: .deft/core/skills/deft-directive-pre-pr/SKILL.md
196
- `,
197
- },
198
- {
199
- dir: "deft-directive-sync",
200
- content: `---
201
- name: deft-directive-sync
202
- description: >-
203
- Session-start framework sync skill. Use at the beginning of a session to
204
- pull latest framework updates, validate project files, and confirm alignment
205
- before starting work.
206
- ---
207
-
208
- Read and follow: .deft/core/skills/deft-directive-sync/SKILL.md
209
- `,
210
- },
211
- ];
212
94
  const BARE_SEMVER = /^\d+\.\d+\.\d+([-+][0-9A-Za-z.-]+)?$/;
213
95
  export function buildInstallManifestText(fields) {
214
96
  let effectiveTag = fields.tag;
@@ -376,20 +258,8 @@ export async function writeConsumerVbrief(projectDir, deftDir, io) {
376
258
  return true;
377
259
  }
378
260
  export function writeAgentsSkills(projectDir, io) {
379
- projectionTarget(projectDir, ".agents");
380
- const allExist = AGENTS_SKILLS.every((skill) => existsSync(join(projectDir, ".agents", "skills", skill.dir, "SKILL.md")));
381
- if (allExist) {
382
- io.printf(".agents/skills/ already present — skipping.\n");
383
- return false;
384
- }
385
- for (const skill of AGENTS_SKILLS) {
386
- const path = projectionTarget(projectDir, ".agents", "skills", skill.dir, "SKILL.md");
387
- if (existsSync(path))
388
- continue;
389
- containedProjectWrite(projectDir, path, skill.content);
390
- }
391
- io.printf(".agents/skills/ created — deft skills will be auto-discovered.\n");
392
- return true;
261
+ // Shared inventory with multi-host skill discovery (#75 residual).
262
+ return writeAgentsSkillsFromInventory(projectDir, io);
393
263
  }
394
264
  function hasTopLevelIncludes(content) {
395
265
  if (!content)
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Multi-host thin skill discovery deposit (#75 residual).
3
+ *
4
+ * Mirrors the consumer skill inventory already written to `.agents/skills/`
5
+ * into additional host paths (`.claude/skills/`, `.codex/skills/`,
6
+ * `.github/skills/`, `.cursor/skills/`). Thin pointers only — no full skill
7
+ * body copies. Windows-safe file writes (no elevated symlink requirement).
8
+ *
9
+ * Distinct from epic #55 slash-command deposit (#3054).
10
+ */
11
+ import type { InitDepositIo } from "./constants.js";
12
+ import { type HostSkillDiscoveryPolicy, type SkillDiscoveryHostId } from "./skill-discovery-hosts.js";
13
+ export type { InitDepositIo };
14
+ /**
15
+ * Consumer skill discovery inventory shared by `.agents/skills/` and multi-host
16
+ * deposit. Each entry is a thin SKILL.md pointer into `.deft/core/…` — never a
17
+ * full skill body. Keep this list the single SoT for install-time discovery.
18
+ */
19
+ export declare const CONSUMER_SKILL_DISCOVERY_INVENTORY: ReadonlyArray<{
20
+ dir: string;
21
+ content: string;
22
+ }>;
23
+ /** Max bytes for a thin pointer body — fat full-skill copies fail this guard. */
24
+ export declare const MAX_THIN_SKILL_POINTER_BYTES = 1200;
25
+ /**
26
+ * True when content is a thin discovery pointer (not an inlined skill body).
27
+ * Managed deposit must stay pointer-shaped so updates do not rot full copies.
28
+ */
29
+ export declare function isThinSkillPointer(content: string): boolean;
30
+ export interface MultiHostSkillDiscoveryDepositResult {
31
+ readonly changed: boolean;
32
+ /** Repo-relative posix paths written or rewritten. */
33
+ readonly changedPaths: string[];
34
+ /** Hosts that received at least one write. */
35
+ readonly hostsTouched: SkillDiscoveryHostId[];
36
+ /** Hosts skipped because `plan.policy.hostSkillDiscovery.<host>` is false. */
37
+ readonly hostsSkipped: SkillDiscoveryHostId[];
38
+ }
39
+ export interface WriteMultiHostSkillDiscoveryOptions {
40
+ /** Override policy (tests); default loads from PROJECT-DEFINITION. */
41
+ policy?: HostSkillDiscoveryPolicy;
42
+ /**
43
+ * Skill inventory to deposit. Defaults to the shared consumer inventory
44
+ * (same set as `.agents/skills/`).
45
+ */
46
+ inventory?: ReadonlyArray<{
47
+ dir: string;
48
+ content: string;
49
+ }>;
50
+ }
51
+ /**
52
+ * Deposit thin skill discovery pointers into enabled multi-host paths.
53
+ * Idempotent: skips write when on-disk content already matches. Never creates
54
+ * symlinks (Windows-safe without elevation).
55
+ */
56
+ export declare function writeMultiHostSkillDiscovery(projectDir: string, io: InitDepositIo, options?: WriteMultiHostSkillDiscoveryOptions): MultiHostSkillDiscoveryDepositResult;
57
+ /**
58
+ * Shared inventory helper for `.agents/skills/` (canonical) deposit.
59
+ * Returns true when any pointer was created (matching writeAgentsSkills).
60
+ */
61
+ export declare function writeAgentsSkillsFromInventory(projectDir: string, io: InitDepositIo, inventory?: ReadonlyArray<{
62
+ dir: string;
63
+ content: string;
64
+ }>): boolean;
65
+ //# sourceMappingURL=skill-discovery-deposit.d.ts.map