@deftai/directive-core 0.90.0 → 0.92.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.
- package/dist/cache/fetch.js +3 -2
- package/dist/cache/io.d.ts +13 -2
- package/dist/cache/io.js +36 -7
- package/dist/cache/operations.js +5 -3
- package/dist/doctor/main.js +37 -0
- package/dist/doctor/openclaw-skills.d.ts +42 -8
- package/dist/doctor/openclaw-skills.js +281 -38
- package/dist/eval/health.d.ts +10 -1
- package/dist/eval/health.js +16 -16
- package/dist/hooks/dispatcher.d.ts +6 -1
- package/dist/hooks/dispatcher.js +30 -0
- package/dist/init-deposit/gitignore.js +3 -0
- package/dist/init-deposit/hygiene.d.ts +43 -1
- package/dist/init-deposit/hygiene.js +112 -7
- package/dist/init-deposit/init-deposit.d.ts +5 -0
- package/dist/init-deposit/init-deposit.js +37 -2
- package/dist/init-deposit/scaffold.js +3 -1
- package/dist/intake/github-auth-modes.d.ts +1 -1
- package/dist/intake/github-auth-modes.js +25 -3
- package/dist/intake/issue-ingest-cli.js +13 -0
- package/dist/intake/reconcile-issues-cli.js +13 -0
- package/dist/orchestration/probe-session.d.ts +5 -1
- package/dist/orchestration/probe-session.js +24 -13
- package/dist/platform/agents-md.js +1 -1
- package/dist/policy/deft-directive-disable.d.ts +86 -0
- package/dist/policy/deft-directive-disable.js +167 -0
- package/dist/policy/delivery-branch.d.ts +33 -0
- package/dist/policy/delivery-branch.js +124 -0
- package/dist/policy/index.d.ts +2 -0
- package/dist/policy/index.js +17 -1
- package/dist/policy/plan-extensions.d.ts +10 -0
- package/dist/policy/plan-extensions.js +16 -0
- package/dist/pr-closing-keywords/detect.d.ts +13 -0
- package/dist/pr-closing-keywords/detect.js +73 -8
- package/dist/pr-closing-keywords/index.d.ts +2 -2
- package/dist/pr-closing-keywords/index.js +1 -1
- package/dist/pr-closing-keywords/main.js +119 -90
- package/dist/pr-closing-keywords/types.d.ts +10 -0
- package/dist/render/constants.d.ts +16 -0
- package/dist/render/constants.js +16 -1
- package/dist/render/export-spec.d.ts +7 -1
- package/dist/render/export-spec.js +51 -5
- package/dist/render/index.d.ts +3 -2
- package/dist/render/index.js +2 -2
- package/dist/render/roadmap-render.js +164 -60
- package/dist/render/scope-outlook.d.ts +5 -0
- package/dist/render/scope-outlook.js +3 -0
- package/dist/render/spec-render.d.ts +28 -2
- package/dist/render/spec-render.js +111 -14
- package/dist/render/text-utils.d.ts +6 -0
- package/dist/render/text-utils.js +23 -0
- package/dist/scm/binary.d.ts +3 -0
- package/dist/scm/binary.js +10 -2
- package/dist/scm/call.d.ts +5 -0
- package/dist/scm/call.js +5 -0
- package/dist/scm/index.d.ts +1 -0
- package/dist/scm/index.js +1 -0
- package/dist/scm/main.d.ts +5 -0
- package/dist/scm/main.js +27 -0
- package/dist/scm/readiness-cli.d.ts +24 -0
- package/dist/scm/readiness-cli.js +85 -0
- package/dist/scm/readiness.d.ts +104 -0
- package/dist/scm/readiness.js +421 -0
- package/dist/scope/batch-promote.d.ts +26 -0
- package/dist/scope/batch-promote.js +167 -0
- package/dist/scope/brief-io.d.ts +3 -1
- package/dist/scope/brief-io.js +5 -3
- package/dist/scope/delivery-evidence.d.ts +112 -0
- package/dist/scope/delivery-evidence.js +419 -0
- package/dist/scope/index.d.ts +2 -0
- package/dist/scope/index.js +2 -0
- package/dist/scope/main.d.ts +7 -0
- package/dist/scope/main.js +155 -9
- package/dist/scope/registry-artifact-sync.js +4 -1
- package/dist/scope/transition.d.ts +11 -1
- package/dist/scope/transition.js +30 -4
- package/dist/scope/wip-cap-check.d.ts +6 -0
- package/dist/scope/wip-cap-check.js +14 -2
- package/dist/session/ritual-sentinel.js +21 -12
- package/dist/session/session-start-hook.d.ts +3 -0
- package/dist/session/session-start-hook.js +21 -0
- package/dist/session/session-start.d.ts +7 -0
- package/dist/session/session-start.js +85 -0
- package/dist/swarm/complete-cohort.d.ts +20 -1
- package/dist/swarm/complete-cohort.js +56 -9
- package/dist/swarm/finalize-cohort-cli.js +9 -0
- package/dist/swarm/finalize-cohort.d.ts +8 -0
- package/dist/swarm/finalize-cohort.js +217 -21
- package/dist/triage/welcome/index.d.ts +1 -1
- package/dist/triage/welcome/index.js +1 -1
- package/dist/triage/welcome/onboard.js +7 -1
- package/dist/triage/welcome/prior-state.d.ts +7 -0
- package/dist/triage/welcome/prior-state.js +16 -2
- package/dist/triage/welcome/writers.d.ts +10 -0
- package/dist/triage/welcome/writers.js +72 -2
- package/dist/user-config/experimental-rules.d.ts +43 -0
- package/dist/user-config/experimental-rules.js +162 -0
- package/dist/user-config/index.d.ts +1 -0
- package/dist/user-config/index.js +1 -0
- package/dist/verify-source/contained-writes.js +1 -1
- package/package.json +3 -3
package/dist/cache/fetch.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
|
-
import { join, resolve } from "node:path";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
import { ContainedWriteError, containedWrite } from "../fs/contained-write.js";
|
|
4
4
|
import { GhRestError, InvalidRepoError, restIssueView, runGhApi, } from "../scm/gh-rest.js";
|
|
5
5
|
import { DEFAULT_BATCH_SIZE, DEFAULT_DELAY_MS } from "./constants.js";
|
|
@@ -45,7 +45,8 @@ export function writeOpenInventoryStamp(options) {
|
|
|
45
45
|
fetched_at: utcIso(clock, fetchedAt),
|
|
46
46
|
open_count: 0,
|
|
47
47
|
};
|
|
48
|
-
|
|
48
|
+
// #3042: contain stamp write against project root (parent of cacheRoot).
|
|
49
|
+
atomicWriteText(openInventoryStampPath(options.cacheRoot, options.source, options.repo), `${JSON.stringify(payload)}\n`, { projectRoot: dirname(resolve(options.cacheRoot)) });
|
|
49
50
|
}
|
|
50
51
|
export const REST_MAX_PER_PAGE = 100;
|
|
51
52
|
export const REST_PAGINATION_MAX_PAGES = 100;
|
package/dist/cache/io.d.ts
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { tmpdir } from "node:os";
|
|
2
|
+
export interface AtomicWriteTextOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Project / checkout root used as the containment boundary (#3042).
|
|
5
|
+
* When set, refuses symlink parents and out-of-root targets before temp+rename.
|
|
6
|
+
* Prefer always passing this for product sinks (brief stay-path, agents refresh, cache).
|
|
7
|
+
* When omitted, falls back to parent-dir containment (legacy test / low-risk helpers).
|
|
8
|
+
*/
|
|
9
|
+
readonly projectRoot?: string;
|
|
10
|
+
}
|
|
2
11
|
/**
|
|
3
12
|
* Write text via tempfile + rename (mirrors Python `_atomic_write_text`).
|
|
4
|
-
* #2951 Phase 2: temp payload write uses containedWrite
|
|
13
|
+
* #2951 Phase 2: temp payload write uses containedWrite.
|
|
14
|
+
* #3042: when `projectRoot` is set, containment root is projectRoot (not dirname(path))
|
|
15
|
+
* so force-added lifecycle / cache directory symlinks fail closed.
|
|
5
16
|
*/
|
|
6
|
-
export declare function atomicWriteText(path: string, text: string): void;
|
|
17
|
+
export declare function atomicWriteText(path: string, text: string, options?: AtomicWriteTextOptions): void;
|
|
7
18
|
/**
|
|
8
19
|
* Append one JSON audit record (mirrors `_append_audit`).
|
|
9
20
|
* #2951 Phase 2: product write sink routes through containedWrite.
|
package/dist/cache/io.js
CHANGED
|
@@ -3,24 +3,53 @@ import { mkdirSync, renameSync, rmSync, statSync, utimesSync } from "node:fs";
|
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { basename, dirname, join, resolve } from "node:path";
|
|
5
5
|
import { containedWrite } from "../fs/contained-write.js";
|
|
6
|
+
import { assertWriteTargetSafe } from "../fs/projection-containment.js";
|
|
6
7
|
import { pythonJsonLine } from "./json.js";
|
|
7
8
|
/**
|
|
8
9
|
* Write text via tempfile + rename (mirrors Python `_atomic_write_text`).
|
|
9
|
-
* #2951 Phase 2: temp payload write uses containedWrite
|
|
10
|
+
* #2951 Phase 2: temp payload write uses containedWrite.
|
|
11
|
+
* #3042: when `projectRoot` is set, containment root is projectRoot (not dirname(path))
|
|
12
|
+
* so force-added lifecycle / cache directory symlinks fail closed.
|
|
10
13
|
*/
|
|
11
|
-
export function atomicWriteText(path, text) {
|
|
12
|
-
const
|
|
14
|
+
export function atomicWriteText(path, text, options = {}) {
|
|
15
|
+
const targetAbs = resolve(path);
|
|
16
|
+
const dir = dirname(targetAbs);
|
|
17
|
+
const tmpBase = `${basename(targetAbs)}.${randomBytes(4).toString("hex")}.tmp`;
|
|
18
|
+
const tmp = join(dir, tmpBase);
|
|
19
|
+
if (options.projectRoot !== undefined) {
|
|
20
|
+
// Contain against projectRoot (parent-as-root fix #3042 / authz writeJsonContained pattern).
|
|
21
|
+
const root = resolve(options.projectRoot);
|
|
22
|
+
assertWriteTargetSafe(root, targetAbs);
|
|
23
|
+
try {
|
|
24
|
+
containedWrite({
|
|
25
|
+
root,
|
|
26
|
+
target: tmp,
|
|
27
|
+
data: text,
|
|
28
|
+
mode: "create",
|
|
29
|
+
});
|
|
30
|
+
renameSync(tmp, targetAbs);
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
try {
|
|
34
|
+
rmSync(tmp, { force: true });
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
/* v8 ignore next -- best-effort cleanup */
|
|
38
|
+
}
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Legacy: parent-dir containment when no projectRoot (unit helpers / transitional call sites).
|
|
13
44
|
mkdirSync(dir, { recursive: true });
|
|
14
|
-
const tmpName = `${basename(path)}.${randomBytes(4).toString("hex")}.tmp`;
|
|
15
|
-
const tmp = join(dir, tmpName);
|
|
16
45
|
try {
|
|
17
46
|
containedWrite({
|
|
18
47
|
root: resolve(dir),
|
|
19
|
-
target:
|
|
48
|
+
target: tmpBase,
|
|
20
49
|
data: text,
|
|
21
50
|
mode: "create",
|
|
22
51
|
});
|
|
23
|
-
renameSync(tmp,
|
|
52
|
+
renameSync(tmp, targetAbs);
|
|
24
53
|
}
|
|
25
54
|
catch (err) {
|
|
26
55
|
try {
|
package/dist/cache/operations.js
CHANGED
|
@@ -129,14 +129,16 @@ export function cachePut(source, key, raw, options = {}) {
|
|
|
129
129
|
incomingBytes: incomingDelta,
|
|
130
130
|
});
|
|
131
131
|
}
|
|
132
|
-
|
|
132
|
+
// #3042: contain cache entry writes against project root (parent of cacheRoot).
|
|
133
|
+
const projectRoot = dirname(resolve(cacheRoot));
|
|
134
|
+
atomicWriteText(join(edir, "raw.json"), rawText, { projectRoot });
|
|
133
135
|
const authoritativeSize = fileSize(join(edir, "raw.json"));
|
|
134
136
|
const rendered = renderContent(source, raw);
|
|
135
137
|
const scanResult = scan(rendered, utcIso(clock, fetched));
|
|
136
138
|
const contentPath = join(edir, "content.md");
|
|
137
139
|
let contentWritten = false;
|
|
138
140
|
if (scanResult.passed) {
|
|
139
|
-
atomicWriteText(contentPath, scanResult.transformed_content);
|
|
141
|
+
atomicWriteText(contentPath, scanResult.transformed_content, { projectRoot });
|
|
140
142
|
contentWritten = true;
|
|
141
143
|
}
|
|
142
144
|
else if (existsSync(contentPath)) {
|
|
@@ -158,7 +160,7 @@ export function cachePut(source, key, raw, options = {}) {
|
|
|
158
160
|
clock,
|
|
159
161
|
});
|
|
160
162
|
validateMeta(meta);
|
|
161
|
-
atomicWriteText(join(edir, "meta.json"), pythonJsonDump(meta));
|
|
163
|
+
atomicWriteText(join(edir, "meta.json"), pythonJsonDump(meta), { projectRoot });
|
|
162
164
|
appendAudit({
|
|
163
165
|
event: "cache:put",
|
|
164
166
|
source,
|
package/dist/doctor/main.js
CHANGED
|
@@ -4,6 +4,7 @@ import { VBRIEF_VERSION } from "@deftai/directive-types";
|
|
|
4
4
|
import { evaluate as evaluateAgentsMdAdvisory } from "../agents-md-advisory/evaluate.js";
|
|
5
5
|
import { contentRoot } from "../content-root.js";
|
|
6
6
|
import { resolveProjectDefinitionPath } from "../layout/resolve.js";
|
|
7
|
+
import { DEFT_DIRECTIVE_DISABLE_FLAG_NAME, DEFT_DIRECTIVE_DISABLE_STATUS, DEFT_DIRECTIVE_DISABLE_TRACKED_WARNING, detectDeftDirectiveDisable, formatDeftDirectiveDisableMessage, isDeftDirectiveDisableActive, } from "../policy/deft-directive-disable.js";
|
|
7
8
|
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";
|
|
8
9
|
import { describeShadowedPlanExtension, detectShadowedPlanExtensions, } from "../policy/plan-extensions.js";
|
|
9
10
|
import { loadProjectDefinition } from "../policy/resolve.js";
|
|
@@ -70,6 +71,42 @@ export function cmdDoctor(args, seams = {}) {
|
|
|
70
71
|
const consumerContext = resolve(projectRoot) !== resolve(frameworkRoot);
|
|
71
72
|
const whichFn = seams.whichFn ?? defaultWhich;
|
|
72
73
|
const nowFn = seams.now ?? (() => new Date());
|
|
74
|
+
// #3039: temporary test kill-switch. Active (untracked) → disabled short-circuit.
|
|
75
|
+
// Tracked/committed flag → warn only and continue normal doctor (no enforcement bypass).
|
|
76
|
+
const killSwitch = detectDeftDirectiveDisable(projectRoot, { skipTrackedCache: true });
|
|
77
|
+
if (killSwitch.present &&
|
|
78
|
+
killSwitch.trackedByGit &&
|
|
79
|
+
!isDeftDirectiveDisableActive(projectRoot, { skipTrackedCache: true })) {
|
|
80
|
+
if (!jsonMode && !quietMode) {
|
|
81
|
+
process.stderr.write(`${DEFT_DIRECTIVE_DISABLE_TRACKED_WARNING}\n`);
|
|
82
|
+
}
|
|
83
|
+
// Continue into full doctor; do not short-circuit.
|
|
84
|
+
}
|
|
85
|
+
else if (isDeftDirectiveDisableActive(projectRoot, { skipTrackedCache: true })) {
|
|
86
|
+
const optOutAlso = detectNoDeftDirective(projectRoot);
|
|
87
|
+
const message = formatDeftDirectiveDisableMessage({
|
|
88
|
+
permanentOptOutAlsoPresent: optOutAlso.present,
|
|
89
|
+
trackedByGit: false,
|
|
90
|
+
});
|
|
91
|
+
if (jsonMode) {
|
|
92
|
+
const payload = {
|
|
93
|
+
status: DEFT_DIRECTIVE_DISABLE_STATUS,
|
|
94
|
+
disabled: true,
|
|
95
|
+
disabled_via: DEFT_DIRECTIVE_DISABLE_FLAG_NAME,
|
|
96
|
+
kill_switch: true,
|
|
97
|
+
inconsistent: false,
|
|
98
|
+
deposit_present: killSwitch.depositPresent,
|
|
99
|
+
tracked_by_git: false,
|
|
100
|
+
permanent_opt_out_also_present: optOutAlso.present,
|
|
101
|
+
message,
|
|
102
|
+
};
|
|
103
|
+
process.stdout.write(`${pythonJsonDump(payload)}\n`);
|
|
104
|
+
}
|
|
105
|
+
else if (!quietMode) {
|
|
106
|
+
process.stdout.write(`${message}\n`);
|
|
107
|
+
}
|
|
108
|
+
return 0;
|
|
109
|
+
}
|
|
73
110
|
// #2926: official root opt-out — short-circuit Directive doctor when clean;
|
|
74
111
|
// diagnose flag+deposit inconsistency (warn; exit dirty).
|
|
75
112
|
const optOut = detectNoDeftDirective(projectRoot);
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OpenClaw always-pin skill detect + doctor --fix wire (#3001).
|
|
2
|
+
* OpenClaw always-pin skill detect + doctor --fix wire (#3001 / #3008).
|
|
3
3
|
*
|
|
4
4
|
* When OpenClaw signals are present, doctor checks the main workspace skills
|
|
5
5
|
* root for the four always-pin skills (#2508). Missing pins emit a warning with
|
|
6
|
-
* remediation `deft doctor --fix`. Under fixMode, pins are
|
|
7
|
-
*
|
|
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.
|
|
8
14
|
*
|
|
9
15
|
* Multi-seat (`workspace-*`) targets only when `--openclaw-all-agents` is set.
|
|
10
16
|
*/
|
|
@@ -29,6 +35,7 @@ export interface OpenClawSkillPinsSeams {
|
|
|
29
35
|
readonly symlinkDir?: (target: string, path: string) => void;
|
|
30
36
|
readonly copyDir?: (src: string, dst: string) => void;
|
|
31
37
|
readonly removePath?: (path: string) => void;
|
|
38
|
+
readonly renamePath?: (from: string, to: string) => void;
|
|
32
39
|
readonly contentRootFor?: (frameworkRoot: string) => string;
|
|
33
40
|
readonly isTty?: () => boolean;
|
|
34
41
|
readonly readYn?: (prompt: string, defaultYes: boolean) => boolean;
|
|
@@ -77,21 +84,48 @@ export declare function listInScopeSkillsDirs(stateDir: string, allAgents: boole
|
|
|
77
84
|
* Resolve content package skills/<id> for a pin.
|
|
78
85
|
*/
|
|
79
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;
|
|
80
92
|
/**
|
|
81
93
|
* Assess which always-pins are present / missing / divergent in a skills root.
|
|
82
94
|
*
|
|
83
|
-
* - present: directory (or symlink) with SKILL.md
|
|
95
|
+
* - present: real directory (or non-escaping symlink) with SKILL.md matching
|
|
96
|
+
* the content package when `contentBase` is supplied
|
|
84
97
|
* - missing: path does not exist
|
|
85
|
-
* - divergent: path exists but is not a usable pin (file, empty dir,
|
|
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)
|
|
86
100
|
*/
|
|
87
|
-
export declare function assessOpenClawPins(skillsDir: string, seams?: Pick<OpenClawSkillPinsSeams, "isDir" | "isFile" | "pathExists" | "lstatKind"
|
|
101
|
+
export declare function assessOpenClawPins(skillsDir: string, seams?: Pick<OpenClawSkillPinsSeams, "isDir" | "isFile" | "pathExists" | "lstatKind">, options?: {
|
|
102
|
+
contentBase?: string;
|
|
103
|
+
}): OpenClawPinAssessment;
|
|
88
104
|
/**
|
|
89
|
-
* Install one pin into a skills root.
|
|
90
|
-
*
|
|
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).
|
|
91
118
|
*/
|
|
92
119
|
export declare function installOpenClawPin(skillId: OpenClawAlwaysPinSkill, sourceDir: string, skillsDir: string, options?: {
|
|
93
120
|
force?: boolean;
|
|
94
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;
|
|
95
129
|
}, seams?: OpenClawSkillPinsSeams): PinInstallResult;
|
|
96
130
|
export interface RunOpenClawSkillPinsOptions {
|
|
97
131
|
readonly frameworkRoot: string;
|