@c4a/context-cli 0.7.20 → 0.7.23
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/README.md +6 -6
- package/README.zh-CN.md +6 -6
- package/cli.js +57 -73
- package/indexers/contracts/profile-contract.json +245 -245
- package/indexers/release-manifest.json +1 -1
- package/package.json +12 -12
- package/plugins/VERSION +1 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/commands/context.md +77 -6
- package/plugins/codex/.codex-plugin/plugin.json +2 -2
- package/plugins/codex/skills/context/SKILL.md +77 -6
- package/plugins/cursor/.cursor-plugin/plugin.json +1 -1
- package/plugins/cursor/commands/c4a-context.md +77 -6
- package/plugins/skills/context/SKILL.md +77 -6
- package/providers/context/codes.yaml +1 -1
- package/providers/context/graphs/indexer.yaml +11 -7
- package/providers/context/graphs/workspace.yaml +5 -0
- package/providers/context/manifest.json +30 -30
- package/providers/context/provider.yaml +1 -1
- package/providers/context/resources/manuals/guides/knowledge-updates.md +5 -1
- package/providers/context/resources/manuals/guides/workspace-prepare.md +4 -0
- package/providers/context/resources/manuals/guides/workspace-restore.md +5 -1
- package/providers/context/resources/procedures/knowledge-review.md +11 -4
- package/providers/context/resources/procedures/knowledge-updates.md +5 -1
- package/providers/context/resources/procedures/package-output.md +4 -0
- package/providers/context/resources/procedures/production-requirements.md +5 -3
- package/providers/context/resources/procedures/source-boundary.md +15 -5
- package/providers/context/resources/procedures/work-start-report.md +19 -6
- package/providers/context/resources/procedures/workspace-prepare.md +4 -0
- package/providers/context/resources/procedures/workspace-restore.md +5 -1
- package/providers/context/skills/resolve-current-indexer-gate/SKILL.md +7 -2
- package/providers/context/skills/run-indexer-lifecycle/SKILL.md +3 -2
- package/providers/context/skills/work-production-stage/SKILL.md +5 -3
package/README.md
CHANGED
|
@@ -20,18 +20,18 @@ an LLM itself.
|
|
|
20
20
|
npm install -g @c4a/context-cli@latest
|
|
21
21
|
context plugin install # global installation
|
|
22
22
|
# Alternatively, install only in a repository:
|
|
23
|
-
context plugin install --local /path/to/repo
|
|
23
|
+
context plugin install --local /path/to/repo --agent auto-detect
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
`--local
|
|
26
|
+
`--local` requires explicit `--agent`: `claude`, `cursor`, `codex`, `all`, `auto-detect`, or `standalone`. The path is a repository root: explicit hosts install into `.claude`, `.cursor`, or `.agents` without detection. `all` installs all three. Only `auto-detect` checks existing `.claude`, `.cursor`, and `.agents` directories in the target repository, never PATH or installed desktop applications; it falls back to `.agents/skills` when none exist. `standalone` instead writes all skills directly to `<path>/skills`, with no commands or host subdirectory. All modes support `--dry-run` and preserve global configuration.
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
Migration from 0.7.20: add `--agent auto-detect` to bare `--local`; for explicit hosts pass the repository root, not its host directory. Global installation is unchanged. Host detection does not verify runtime loading.
|
|
29
29
|
|
|
30
30
|
| Command | Local layout |
|
|
31
31
|
| --- | --- |
|
|
32
|
-
| `context plugin install --local /path/to/repo
|
|
33
|
-
| `context plugin install --local /path/to/repo
|
|
34
|
-
| `context plugin install --local /path/to/repo
|
|
32
|
+
| `context plugin install --local /path/to/repo --agent claude` | Public entries in `commands/`, other skills in `skills/`; internal skills receive `user-invocable: false`, without duplicate entry skills |
|
|
33
|
+
| `context plugin install --local /path/to/repo --agent cursor` | Bundled `c4a-*` commands plus other skills; hiding Providers from the command menu is not guaranteed |
|
|
34
|
+
| `context plugin install --local /path/to/repo --agent codex` | All entries remain skills; bundled `agents/openai.yaml` policies are preserved; no unsupported `commands/` directory |
|
|
35
35
|
|
|
36
36
|
Local entries have no plugin namespace; the host must discover the destination. Use `--dry-run` to preview. Refresh only replaces unmodified managed content; unrelated files remain and conflicting/customized entries are rejected. Choose a fresh host directory when switching from a standalone installation to command entries, to avoid duplicates. `plugin status` still inspects global hosts only. Invocation metadata is not a CLI permission or security boundary.
|
|
37
37
|
|
package/README.zh-CN.md
CHANGED
|
@@ -16,18 +16,18 @@
|
|
|
16
16
|
npm install -g @c4a/context-cli@latest
|
|
17
17
|
context plugin install # 全局安装
|
|
18
18
|
# 或者,只安装到仓库:
|
|
19
|
-
context plugin install --local /path/to/repo
|
|
19
|
+
context plugin install --local /path/to/repo --agent auto-detect
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
`--local
|
|
22
|
+
`--local` 必须显式搭配 `--agent`:`claude`、`cursor`、`codex`、`all`、`auto-detect` 或 `standalone`。路径为仓库根;指定宿主直接写入对应 `.claude`、`.cursor`、`.agents` 子目录,不检测是否安装宿主。`all` 全装;只有 `auto-detect` 检测目标仓库已有的 `.claude`、`.cursor`、`.agents` 目录,不检测 PATH 或桌面应用;均不存在时兜底 `.agents/skills`。`standalone` 则直接写入 `<path>/skills`,不生成 commands 或宿主子目录。均支持 `--dry-run`,不改全局配置。
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
从 0.7.20 迁移:裸 `--local` 补充 `--agent auto-detect`;指定宿主时传仓库根,不再传宿主目录。全局安装不变。自动探测不代表宿主已加载,安装后需刷新宿主。
|
|
25
25
|
|
|
26
26
|
| 命令 | 局部目录与行为 |
|
|
27
27
|
| --- | --- |
|
|
28
|
-
| `context plugin install --local /path/to/repo
|
|
29
|
-
| `context plugin install --local /path/to/repo
|
|
30
|
-
| `context plugin install --local /path/to/repo
|
|
28
|
+
| `context plugin install --local /path/to/repo --agent claude` | `commands/` 放公开入口;`skills/` 放其他技能,内部技能设置 `user-invocable: false`,不重复安装入口 Skill |
|
|
29
|
+
| `context plugin install --local /path/to/repo --agent cursor` | `commands/` 使用随包的 `c4a-*` 命令;`skills/` 放其他技能,不保证隐藏 Provider 的菜单入口 |
|
|
30
|
+
| `context plugin install --local /path/to/repo --agent codex` | 全部入口保留为 skills,保留随包的 `agents/openai.yaml` 调用策略,不生成无效的 `commands/` |
|
|
31
31
|
|
|
32
32
|
宿主必须支持发现目标位置。局部入口没有插件命名空间。`--dry-run` 只预览;重复安装仅刷新本命令管理且未被修改的内容,保留无关文件;同名自定义内容或本地修改会报冲突。已有通用 skills 目录切换为 command 宿主时,请选择新目录,避免重复入口。`plugin status` 仍只检查全局宿主状态。调用元数据控制宿主入口展示/自动调用,不是 CLI 权限或安全隔离。
|
|
33
33
|
|
package/cli.js
CHANGED
|
@@ -79504,7 +79504,7 @@ function productionPlanMarkdown(stage) {
|
|
|
79504
79504
|
...!stage.report_approved && stage.planning_complete ? [
|
|
79505
79505
|
`If the user requests changes, edit ${productionAgentDirectory(stage.id)}/submissions/plan.yaml using ${join30(directory, "planning.schema.json")}.`,
|
|
79506
79506
|
`Resubmit: context action complete-current --revision ${stage.id} --input ${productionAgentDirectory(stage.id)}/submissions/plan.yaml --format json`,
|
|
79507
|
-
"Then present the updated report and
|
|
79507
|
+
"Then present the updated report and apply context.gate.work_start_scope; an old decision does not approve changed article goals.",
|
|
79508
79508
|
""
|
|
79509
79509
|
] : [],
|
|
79510
79510
|
...stage.gaps.map((gap) => `- ${gap.scope}: ${gap.reason}`),
|
|
@@ -80697,7 +80697,7 @@ async function completeProductionSubmission(input) {
|
|
|
80697
80697
|
if (!stage || stage.id !== input.stage)
|
|
80698
80698
|
throw submissionStateError("stale-production-stage", "Task stage no longer exists. Start a new production run; do not reuse a stale submission.");
|
|
80699
80699
|
if (!stage.report_approved)
|
|
80700
|
-
throw submissionStateError("production-report-approval-required", "Present the planned report and
|
|
80700
|
+
throw submissionStateError("production-report-approval-required", "Present the planned report and apply context.gate.work_start_scope before submitting bulk writing.");
|
|
80701
80701
|
if (stage.delivery)
|
|
80702
80702
|
throw submissionStateError("production-delivery-paused", "Writing is paused for delivery. Finish Review and build, or run context run --resume-writing --format json; existing task inputs remain valid.");
|
|
80703
80703
|
if ((await readMaintenance(input.projectRoot)).active)
|
|
@@ -83457,8 +83457,8 @@ function renderAgents(projectName, language) {
|
|
|
83457
83457
|
"",
|
|
83458
83458
|
"## 工作区契约",
|
|
83459
83459
|
"",
|
|
83460
|
-
"版本以 package.json.version 为准。正式内容变化收尾时通过 context version inspect / record 同步递增版本并生成 changelog.yaml 和 CHANGELOG.md,具体说明由 Agent 根据 diff 和会话撰写。新增模块或扩大知识覆盖升 minor,普通修补、目录和正式状态变化升 patch;major 只由人工明确指定。.tmp 进度不算变化,build 只记录 hash
|
|
83461
|
-
"版本差异使用 Git 比较正文、结构、资源、导航和模板;可通过 version inspect --base 指定交付 commit/tag
|
|
83460
|
+
"版本以 package.json.version 为准。正式内容变化收尾时通过 context version inspect / record 同步递增版本并生成 changelog.yaml 和 CHANGELOG.md,具体说明由 Agent 根据 diff 和会话撰写。新增模块或扩大知识覆盖升 minor,普通修补、目录和正式状态变化升 patch;major 只由人工明确指定。.tmp 进度不算变化,build 只记录 hash。仅主协调者记录版本;版本记录本身不提交或发布,后续交付按本次授权和已安装的分发技能执行。触发来源必填;触发用户优先使用会话中明确的飞书显示名,否则由 CLI 读取 Git 用户名。",
|
|
83461
|
+
"版本差异使用 Git 比较正文、结构、资源、导航和模板;可通过 version inspect --base 指定交付 commit/tag。构建预览不锁定版本,已发布内容发生变化时必须递增版本。无需维护根目录 Context 版本、构建或发布回执。",
|
|
83462
83462
|
"每个版本的 Changelog 详情不得超过 1500 字:标题、变更列表、触发来源说明及用户显示名的可见字符合计计数,含标点,不计协议字段名、版本号和日期。超出时由 Agent 在提交前合并同类变化、删除重复过程描述,压缩至上限内;保留主要变化、影响和触发来源,不直接截断,也不把一轮拆成多个版本规避限制。",
|
|
83463
83463
|
"",
|
|
83464
83464
|
"- 通过已安装的 Context Skill 开始或恢复工作;直接使用 CLI 时,从 `context status --format json` 开始。",
|
|
@@ -83503,8 +83503,8 @@ function renderAgents(projectName, language) {
|
|
|
83503
83503
|
"",
|
|
83504
83504
|
"## Workspace Contract",
|
|
83505
83505
|
"",
|
|
83506
|
-
"package.json.version is the workspace version. At formal-content completion, use context version inspect / record to increment SemVer and generate changelog.yaml and CHANGELOG.md together. Write descriptions from the diff and conversation. Added modules/coverage increment minor; repairs, navigation and persistent status changes increment patch. Major requires an explicit user instruction. Ignore .tmp progress; build only records hashes. The coordinator alone records versions
|
|
83507
|
-
"Compare bodies, structure, assets, navigation and templates using Git; version inspect --base selects a delivery commit/tag. Preview builds do not seal versions.
|
|
83506
|
+
"package.json.version is the workspace version. At formal-content completion, use context version inspect / record to increment SemVer and generate changelog.yaml and CHANGELOG.md together. Write descriptions from the diff and conversation. Added modules/coverage increment minor; repairs, navigation and persistent status changes increment patch. Major requires an explicit user instruction. Ignore .tmp progress; build only records hashes. The coordinator alone records versions; recording a version does not commit or publish, and later delivery follows this task's authorization and the installed distribution skill. Triggers are required; use an explicitly known conversational Lark display name, otherwise let CLI use Git user.name.",
|
|
83507
|
+
"Compare bodies, structure, assets, navigation and templates using Git; version inspect --base selects a delivery commit/tag. Preview builds do not seal versions. Changes to already published content must increment the version. No root Context version/build/publication receipts are required.",
|
|
83508
83508
|
"Each version's changelog details must total at most 1500 visible characters, including punctuation across the title, changes, trigger descriptions and user display name; exclude protocol keys, version and date. Before submission, compress longer entries by merging related changes and removing repeated process narration. Preserve the main changes, impact and triggers; never truncate blindly or split one iteration into multiple versions to evade the limit.",
|
|
83509
83509
|
"",
|
|
83510
83510
|
"- Start or resume through the installed Context Skill. When using the CLI directly, begin with `context status --format json`.",
|
|
@@ -93106,7 +93106,7 @@ async function productionWorkflowRoute(input) {
|
|
|
93106
93106
|
revision,
|
|
93107
93107
|
reason_code: resolved.reasonCode,
|
|
93108
93108
|
availability: resolved.availability,
|
|
93109
|
-
summary: report ? `Present the report and
|
|
93109
|
+
summary: report ? `Present the report and apply context.gate.work_start_scope. After the applicable scope decision, write {stage: ${stage.id}, decision: approved} to ${path2}.` : writing ? "Read the issued task directories. Coordinate them sequentially unless this caller supports independent Agents; only the coordinator submits shared state." : repair ? "Add revision tasks for rejected articles using the Review feedback; accepted production responsibilities remain unchanged." : investigate ? `Review pending configured scopes: ${stage.pending_scopes.filter((scope2) => !stage.gaps.some((gap2) => gap2.scope === scope2)).join(", ")}. Check their relevance to the current request and existing approved content before assigning investigation. Submit supported article tasks and remaining pending_scopes; do not infer missing articles from this list or repeat accepted work. If the requested articles are already accepted, context run --deliver --format json enters their Review while retaining unrelated pending scopes.` : resolved.node === "resolve-production-gap" ? `Source availability gaps: ${stage.gaps.map((gap2) => `${gap2.scope}: ${gap2.reason}`).join("; ")}. These failures do not establish missing knowledge or a new investigation assignment. Identify which sources the current task actually depends on; report unrelated configured-source failures separately. Preserve the configuration. To review completed articles independently, use context run --deliver --format json; this retains pending scopes and does not approve or publish content. If these sources are required, use context source recovery-plan --format json and context source restore with explicit local or clone decisions before preparation.` : "Prepare the current stage's eligible task directories.",
|
|
93110
93110
|
commands: report || prepare || writing || repair || investigate || gap ? [{
|
|
93111
93111
|
command: command2,
|
|
93112
93112
|
effect: "write",
|
|
@@ -98631,7 +98631,7 @@ function resolveDocsFetchPlan(requested, runner2) {
|
|
|
98631
98631
|
}
|
|
98632
98632
|
return capabilitiesPromise.then((capabilities) => {
|
|
98633
98633
|
if (!capabilities.supportsDocFormat) {
|
|
98634
|
-
throw new LarkCliError(`${LARK_BIN} docs +fetch does not support --doc-format xml;
|
|
98634
|
+
throw new LarkCliError(`${LARK_BIN} docs +fetch does not support --doc-format xml; a compatible @larksuite/cli is required to capture Lark sources`, 0, "");
|
|
98635
98635
|
}
|
|
98636
98636
|
return { apiVersion: capabilities.apiVersion, docFormat: "xml" };
|
|
98637
98637
|
});
|
|
@@ -98642,7 +98642,7 @@ function docsFetchFailureMessage(stderr, apiVersion) {
|
|
|
98642
98642
|
const mentionsV2 = /api-version|--api-version|v2|deprecated|lark-cli update/iu.test(stderr);
|
|
98643
98643
|
if (apiVersion === "v1" && mentionsV2) {
|
|
98644
98644
|
return `${base}
|
|
98645
|
-
Detected docs API v2 guidance from lark-cli
|
|
98645
|
+
Detected docs API v2 guidance from lark-cli; a compatible CLI with \`--api-version v2\` is required.`;
|
|
98646
98646
|
}
|
|
98647
98647
|
return base;
|
|
98648
98648
|
}
|
|
@@ -98707,7 +98707,7 @@ function extractDocsFetchContent(payload, requestedFormat) {
|
|
|
98707
98707
|
const withTitle = (result) => title2 === undefined ? result : { ...result, title: title2 };
|
|
98708
98708
|
if (markdown !== undefined) {
|
|
98709
98709
|
if (requestedFormat === "xml") {
|
|
98710
|
-
throw new LarkCliError(`${LARK_BIN} docs +fetch returned Markdown despite --doc-format xml; capture stopped because the response cannot provide auditable rich-block fidelity.
|
|
98710
|
+
throw new LarkCliError(`${LARK_BIN} docs +fetch returned Markdown despite --doc-format xml; capture stopped because the response cannot provide auditable rich-block fidelity. Use a compatible CLI and retry.`, 0, "");
|
|
98711
98711
|
}
|
|
98712
98712
|
return withTitle({ body: markdown, format: "markdown", recognizedShape: true });
|
|
98713
98713
|
}
|
|
@@ -99038,7 +99038,7 @@ ${body2}`,
|
|
|
99038
99038
|
};
|
|
99039
99039
|
}
|
|
99040
99040
|
var LARK_BIN = "lark-cli", MAX_FETCH_PAGES = 50, MAX_STRUCTURAL_FETCH_ATTEMPTS = 2, LarkCliNotInstalledError, LarkCliError, defaultRunner = (args, options) => new Promise((resolve8, reject) => {
|
|
99041
|
-
const child = spawn4(LARK_BIN, args, {
|
|
99041
|
+
const child = spawn4(process.env.CONTEXT_LARK_CLI_BIN?.trim() || LARK_BIN, args, {
|
|
99042
99042
|
...options?.cwd === undefined ? {} : { cwd: options.cwd },
|
|
99043
99043
|
stdio: ["ignore", "pipe", "pipe"]
|
|
99044
99044
|
});
|
|
@@ -99193,6 +99193,7 @@ function larkTarget(entry) {
|
|
|
99193
99193
|
}
|
|
99194
99194
|
function larkErrorRecovery(error, sourceName) {
|
|
99195
99195
|
const message = error instanceof Error ? error.message : String(error);
|
|
99196
|
+
const localCliRecovery = `Install @larksuite/cli in a private directory with \`npm install --prefix "$HOME/.cache/context/lark-cli" @larksuite/cli@latest\`, then rerun \`CONTEXT_LARK_CLI_BIN="$HOME/.cache/context/lark-cli/node_modules/.bin/lark-cli" context run capture:lark:${sourceName}\`. Keep this variable on subsequent Context commands that access Lark; do not replace the global lark-cli.`;
|
|
99196
99197
|
const environmentIssue = detectExternalEnvironmentIssue(message);
|
|
99197
99198
|
if (environmentIssue !== undefined) {
|
|
99198
99199
|
return {
|
|
@@ -99207,13 +99208,13 @@ function larkErrorRecovery(error, sourceName) {
|
|
|
99207
99208
|
if (error instanceof LarkCliNotInstalledError || /not installed|ENOENT/iu.test(message)) {
|
|
99208
99209
|
return {
|
|
99209
99210
|
reasonCode: "external.dependency-missing",
|
|
99210
|
-
next:
|
|
99211
|
+
next: localCliRecovery
|
|
99211
99212
|
};
|
|
99212
99213
|
}
|
|
99213
99214
|
if (/does not support --doc-format|api-version|deprecated|unsupported tool version|tool version unsupported/iu.test(message)) {
|
|
99214
99215
|
return {
|
|
99215
99216
|
reasonCode: "external.tool-version-unsupported",
|
|
99216
|
-
next:
|
|
99217
|
+
next: localCliRecovery
|
|
99217
99218
|
};
|
|
99218
99219
|
}
|
|
99219
99220
|
if (/empty|unsupported payload shape|not JSON|parse/iu.test(message)) {
|
|
@@ -100691,7 +100692,7 @@ var init_managedDocumentRename = __esm(() => {
|
|
|
100691
100692
|
|
|
100692
100693
|
// src/cli.ts
|
|
100693
100694
|
import { existsSync as existsSync36, realpathSync as realpathSync3 } from "node:fs";
|
|
100694
|
-
import { dirname as
|
|
100695
|
+
import { dirname as dirname49, join as join115 } from "node:path";
|
|
100695
100696
|
import { fileURLToPath as fileURLToPath11, pathToFileURL as pathToFileURL3 } from "node:url";
|
|
100696
100697
|
|
|
100697
100698
|
// ../../node_modules/.bun/commander@11.1.0/node_modules/commander/esm.mjs
|
|
@@ -112690,50 +112691,33 @@ ${frontmatter2}${parts[3]}${content3.slice(parts[0].length)}`);
|
|
|
112690
112691
|
init_cliFeedback();
|
|
112691
112692
|
init_errors3();
|
|
112692
112693
|
init_exitCode();
|
|
112693
|
-
import {
|
|
112694
|
-
import {
|
|
112695
|
-
import { homedir as homedir2 } from "node:os";
|
|
112696
|
-
import { basename as basename13, delimiter, dirname as dirname47, join as join112, resolve as resolve41 } from "node:path";
|
|
112694
|
+
import { lstat as lstat15 } from "node:fs/promises";
|
|
112695
|
+
import { join as join112, resolve as resolve41 } from "node:path";
|
|
112697
112696
|
var HOST_DIRS = { claude: ".claude", cursor: ".cursor", codex: ".agents" };
|
|
112698
|
-
async function detectLocalAgent(agent) {
|
|
112699
|
-
const
|
|
112700
|
-
|
|
112701
|
-
|
|
112702
|
-
|
|
112703
|
-
|
|
112704
|
-
try {
|
|
112705
|
-
if (!(await stat11(file)).isFile())
|
|
112706
|
-
continue;
|
|
112707
|
-
await access6(file, constants7.X_OK);
|
|
112708
|
-
return true;
|
|
112709
|
-
} catch {}
|
|
112710
|
-
}
|
|
112711
|
-
}
|
|
112712
|
-
}
|
|
112713
|
-
if (process.platform === "darwin") {
|
|
112714
|
-
const app = { claude: "Claude.app", cursor: "Cursor.app", codex: "Codex.app" }[agent];
|
|
112715
|
-
if (agent !== "claude") {
|
|
112716
|
-
for (const directory of ["/Applications", join112(homedir2(), "Applications")]) {
|
|
112717
|
-
try {
|
|
112718
|
-
if ((await stat11(join112(directory, app))).isDirectory())
|
|
112719
|
-
return true;
|
|
112720
|
-
} catch {}
|
|
112721
|
-
}
|
|
112697
|
+
async function detectLocalAgent(agent, repo) {
|
|
112698
|
+
const path3 = join112(repo, HOST_DIRS[agent]);
|
|
112699
|
+
try {
|
|
112700
|
+
const entry = await lstat15(path3);
|
|
112701
|
+
if (!entry.isDirectory() || entry.isSymbolicLink()) {
|
|
112702
|
+
throw new ContextError(ExitCode.UserError, `Local host directory is not a regular directory: ${path3}`);
|
|
112722
112703
|
}
|
|
112704
|
+
return true;
|
|
112705
|
+
} catch (error) {
|
|
112706
|
+
if (error.code === "ENOENT")
|
|
112707
|
+
return false;
|
|
112708
|
+
throw error;
|
|
112723
112709
|
}
|
|
112724
|
-
return false;
|
|
112725
112710
|
}
|
|
112726
|
-
async function installAutoLocalSkills(root2, path3, dryRun, detect = detectLocalAgent) {
|
|
112711
|
+
async function installAutoLocalSkills(root2, path3, dryRun, detect = detectLocalAgent, selectedAgent) {
|
|
112727
112712
|
if (!path3.trim())
|
|
112728
112713
|
throw new ContextError(ExitCode.UserError, "--local requires a non-empty repository path", {
|
|
112729
112714
|
category: ErrorCategory.UserInputInvalid,
|
|
112730
|
-
next: "Run context plugin install --local /path/to/repository."
|
|
112715
|
+
next: "Run context plugin install --local /path/to/repository --agent auto-detect."
|
|
112731
112716
|
});
|
|
112732
|
-
const
|
|
112733
|
-
const repo = Object.values(HOST_DIRS).some((name3) => name3 === basename13(requested)) ? dirname47(requested) : requested;
|
|
112717
|
+
const repo = resolve41(path3);
|
|
112734
112718
|
const agents = [];
|
|
112735
112719
|
for (const agent of ["claude", "cursor", "codex"]) {
|
|
112736
|
-
if (await detect(agent))
|
|
112720
|
+
if (selectedAgent ? selectedAgent === "all" || agent === selectedAgent : await detect(agent, repo))
|
|
112737
112721
|
agents.push(agent);
|
|
112738
112722
|
}
|
|
112739
112723
|
const targets = agents.length ? agents.map((agent) => ({ agent, path: join112(repo, HOST_DIRS[agent]) })) : [{ path: join112(repo, ".agents") }];
|
|
@@ -112742,14 +112726,14 @@ async function installAutoLocalSkills(root2, path3, dryRun, detect = detectLocal
|
|
|
112742
112726
|
previews.push(await installLocalSkills(root2, target.path, true, target.agent));
|
|
112743
112727
|
const header = formatFeedback({
|
|
112744
112728
|
symbol: agents.length ? "✓" : "⚠",
|
|
112745
|
-
action: "detected",
|
|
112729
|
+
action: selectedAgent ? "selected" : "detected",
|
|
112746
112730
|
subject: "local agent targets",
|
|
112747
|
-
headline: agents.length ? agents.join(", ") : "No supported
|
|
112731
|
+
headline: agents.length ? agents.join(", ") : "No supported host directory found",
|
|
112748
112732
|
body: [
|
|
112749
112733
|
`repository: ${repo}`,
|
|
112750
112734
|
...targets.map((target) => `${target.agent ?? "standalone"}: ${target.path}`),
|
|
112751
|
-
...!agents.length ? ["Installing only .agents/skills. Configure a supported host to read this directory, or
|
|
112752
|
-
"
|
|
112735
|
+
...!agents.length ? ["Installing only .agents/skills. Configure a supported host to read this directory, or select an explicit --agent with the same repository root."] : [],
|
|
112736
|
+
"Repository directory discovery does not verify runtime skill loading; refresh the host after installation."
|
|
112753
112737
|
]
|
|
112754
112738
|
});
|
|
112755
112739
|
if (dryRun)
|
|
@@ -112769,7 +112753,7 @@ init_cliFeedback();
|
|
|
112769
112753
|
init_errors3();
|
|
112770
112754
|
init_exitCode();
|
|
112771
112755
|
import { existsSync as existsSync35 } from "node:fs";
|
|
112772
|
-
import { dirname as
|
|
112756
|
+
import { dirname as dirname48, join as join114, resolve as resolve42 } from "node:path";
|
|
112773
112757
|
import { fileURLToPath as fileURLToPath10 } from "node:url";
|
|
112774
112758
|
|
|
112775
112759
|
// src/project/pluginInstallTargets.ts
|
|
@@ -112779,8 +112763,8 @@ init_exitCode();
|
|
|
112779
112763
|
import { execFile as execFile13 } from "node:child_process";
|
|
112780
112764
|
import { existsSync as existsSync34 } from "node:fs";
|
|
112781
112765
|
import { cp as cp3, mkdir as mkdir37, readdir as readdir30, readFile as readFile95, rename as rename10, rm as rm25, writeFile as writeFile29 } from "node:fs/promises";
|
|
112782
|
-
import { homedir as
|
|
112783
|
-
import { dirname as
|
|
112766
|
+
import { homedir as homedir2 } from "node:os";
|
|
112767
|
+
import { dirname as dirname47, join as join113 } from "node:path";
|
|
112784
112768
|
import { promisify as promisify13 } from "node:util";
|
|
112785
112769
|
var execFileAsync7 = promisify13(execFile13);
|
|
112786
112770
|
var MARKETPLACE_NAME = "c4a";
|
|
@@ -112834,23 +112818,23 @@ async function claudePluginInstalled(pluginId) {
|
|
|
112834
112818
|
}
|
|
112835
112819
|
}
|
|
112836
112820
|
function codexHome() {
|
|
112837
|
-
return process.env.CODEX_HOME?.trim() || join113(
|
|
112821
|
+
return process.env.CODEX_HOME?.trim() || join113(homedir2(), ".codex");
|
|
112838
112822
|
}
|
|
112839
112823
|
function claudePluginCacheRoot() {
|
|
112840
112824
|
const explicitRoot = process.env[CLAUDE_PLUGIN_CACHE_ROOT_ENV2]?.trim();
|
|
112841
112825
|
if (explicitRoot)
|
|
112842
112826
|
return explicitRoot;
|
|
112843
|
-
const home = process.env[CLAUDE_PLUGIN_CACHE_HOME_ENV2]?.trim() ||
|
|
112827
|
+
const home = process.env[CLAUDE_PLUGIN_CACHE_HOME_ENV2]?.trim() || homedir2();
|
|
112844
112828
|
return join113(home, ".claude", "plugins", "cache");
|
|
112845
112829
|
}
|
|
112846
112830
|
function sharedSkillsRoot() {
|
|
112847
|
-
return process.env[SHARED_SKILLS_ROOT_ENV]?.trim() || join113(
|
|
112831
|
+
return process.env[SHARED_SKILLS_ROOT_ENV]?.trim() || join113(homedir2(), ".agents", "skills");
|
|
112848
112832
|
}
|
|
112849
112833
|
function claudeSkillsRoot() {
|
|
112850
|
-
return process.env[CLAUDE_SKILLS_ROOT_ENV]?.trim() || join113(
|
|
112834
|
+
return process.env[CLAUDE_SKILLS_ROOT_ENV]?.trim() || join113(homedir2(), ".claude", "skills");
|
|
112851
112835
|
}
|
|
112852
112836
|
function cursorPluginRoot() {
|
|
112853
|
-
return process.env[CURSOR_PLUGIN_ROOT_ENV]?.trim() || join113(
|
|
112837
|
+
return process.env[CURSOR_PLUGIN_ROOT_ENV]?.trim() || join113(homedir2(), ".cursor", "plugins", "local", PLUGIN_NAME);
|
|
112854
112838
|
}
|
|
112855
112839
|
function blockHeader(line) {
|
|
112856
112840
|
const match = line.match(/^\s*\[([^\]]+)\]\s*$/u);
|
|
@@ -113089,7 +113073,7 @@ source = ${JSON.stringify(root2)}
|
|
|
113089
113073
|
}
|
|
113090
113074
|
async function ensureCodexPluginEnabled() {
|
|
113091
113075
|
const configPath = join113(codexHome(), "config.toml");
|
|
113092
|
-
await mkdir37(
|
|
113076
|
+
await mkdir37(dirname47(configPath), { recursive: true });
|
|
113093
113077
|
const current2 = await readFile95(configPath, "utf8").catch(() => "");
|
|
113094
113078
|
const next2 = enableCodexPluginConfig(current2);
|
|
113095
113079
|
if (next2 !== current2) {
|
|
@@ -113098,7 +113082,7 @@ async function ensureCodexPluginEnabled() {
|
|
|
113098
113082
|
}
|
|
113099
113083
|
async function ensureCodexLocalMarketplace(root2) {
|
|
113100
113084
|
const configPath = join113(codexHome(), "config.toml");
|
|
113101
|
-
await mkdir37(
|
|
113085
|
+
await mkdir37(dirname47(configPath), { recursive: true });
|
|
113102
113086
|
const current2 = await readFile95(configPath, "utf8").catch(() => "");
|
|
113103
113087
|
const next2 = upsertCodexLocalMarketplaceConfig(current2, root2);
|
|
113104
113088
|
if (next2 !== current2) {
|
|
@@ -113117,7 +113101,7 @@ function codexPluginCacheDir(version3) {
|
|
|
113117
113101
|
return join113(codexHome(), "plugins", "cache", MARKETPLACE_NAME, PLUGIN_NAME, version3);
|
|
113118
113102
|
}
|
|
113119
113103
|
async function replaceDirectoryFromSource(source2, target) {
|
|
113120
|
-
await mkdir37(
|
|
113104
|
+
await mkdir37(dirname47(target), { recursive: true });
|
|
113121
113105
|
const temporary = `${target}.tmp-${process.pid}-${Date.now()}`;
|
|
113122
113106
|
const previous3 = `${target}.previous-${process.pid}-${Date.now()}`;
|
|
113123
113107
|
await rm25(temporary, { recursive: true, force: true });
|
|
@@ -113283,10 +113267,10 @@ function pluginAgentOption(value) {
|
|
|
113283
113267
|
}
|
|
113284
113268
|
function packageCandidateDirs() {
|
|
113285
113269
|
const dirs = [];
|
|
113286
|
-
let dir =
|
|
113270
|
+
let dir = dirname48(fileURLToPath10(import.meta.url));
|
|
113287
113271
|
for (let index2 = 0;index2 < 8; index2++) {
|
|
113288
113272
|
dirs.push(dir);
|
|
113289
|
-
const parent =
|
|
113273
|
+
const parent = dirname48(dir);
|
|
113290
113274
|
if (parent === dir)
|
|
113291
113275
|
break;
|
|
113292
113276
|
dir = parent;
|
|
@@ -113455,14 +113439,14 @@ function registerPluginCommands(program2) {
|
|
|
113455
113439
|
const agent = pluginAgentOption(options.agent);
|
|
113456
113440
|
process.stdout.write(formatPluginStatusResult(await runPluginStatusCommand({ agent })));
|
|
113457
113441
|
});
|
|
113458
|
-
plugin.command("install").description("Install globally by default, or copy standalone skills with --local <path>").option("--agent <agent>", "agent target: claude | codex | cursor | all", "all").option("--local <path>", "
|
|
113442
|
+
plugin.command("install").description("Install globally by default, or copy standalone skills with --local <path>").option("--agent <agent>", "agent target: claude | codex | cursor | all; local only: auto-detect | standalone", "all").option("--local <path>", "Repository root; install selected or detected hosts into their corresponding subdirectories").option("--dry-run", "Preview installation without writing files or configuration").action(async (options, command3) => {
|
|
113459
113443
|
if (options.local !== undefined) {
|
|
113460
|
-
|
|
113461
|
-
|
|
113462
|
-
throw new ContextError(ExitCode.UserError, "--local requires one --agent (claude, cursor or codex), or omit --agent for automatic detection.");
|
|
113444
|
+
if (command3.getOptionValueSource("agent") !== "cli") {
|
|
113445
|
+
throw new ContextError(ExitCode.UserError, "--local requires explicit --agent: claude, cursor, codex, all, auto-detect or standalone.");
|
|
113463
113446
|
}
|
|
113447
|
+
const agent2 = options.agent === "auto-detect" || options.agent === "standalone" ? options.agent : pluginAgentOption(options.agent);
|
|
113464
113448
|
const { pluginsRoot } = await runPluginPathCommand();
|
|
113465
|
-
process.stdout.write(agent2 ? await installLocalSkills(pluginsRoot, String(options.local), options.dryRun === true
|
|
113449
|
+
process.stdout.write(agent2 === "standalone" ? await installLocalSkills(pluginsRoot, String(options.local), options.dryRun === true) : await installAutoLocalSkills(pluginsRoot, String(options.local), options.dryRun === true, undefined, agent2 === "auto-detect" ? undefined : agent2));
|
|
113466
113450
|
return;
|
|
113467
113451
|
}
|
|
113468
113452
|
const agent = pluginAgentOption(options.agent);
|
|
@@ -113550,7 +113534,7 @@ function inferErrorCategory(message) {
|
|
|
113550
113534
|
}
|
|
113551
113535
|
function readQuickstartPath() {
|
|
113552
113536
|
try {
|
|
113553
|
-
let dir =
|
|
113537
|
+
let dir = dirname49(fileURLToPath11(import.meta.url));
|
|
113554
113538
|
for (let i2 = 0;i2 < 8; i2++) {
|
|
113555
113539
|
const candidate = join115(dir, "docs", "quickstart.md");
|
|
113556
113540
|
if (existsSync36(candidate))
|
|
@@ -113558,13 +113542,13 @@ function readQuickstartPath() {
|
|
|
113558
113542
|
const pkg = join115(dir, "package.json");
|
|
113559
113543
|
if (existsSync36(pkg))
|
|
113560
113544
|
return candidate;
|
|
113561
|
-
const parent =
|
|
113545
|
+
const parent = dirname49(dir);
|
|
113562
113546
|
if (parent === dir)
|
|
113563
113547
|
break;
|
|
113564
113548
|
dir = parent;
|
|
113565
113549
|
}
|
|
113566
113550
|
} catch {}
|
|
113567
|
-
return join115(
|
|
113551
|
+
return join115(dirname49(fileURLToPath11(import.meta.url)), "docs", "quickstart.md");
|
|
113568
113552
|
}
|
|
113569
113553
|
var GREEN = "\x1B[32m";
|
|
113570
113554
|
var RESET = "\x1B[0m";
|