kibi-opencode 0.16.0 → 0.19.1
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 +10 -8
- package/dist/e2e-coverage-signals.js +4 -1
- package/dist/enforcement-policy.js +14 -1
- package/dist/init-kibi-alias.js +4 -1
- package/dist/prompt.js +20 -10
- package/dist/repo-posture.js +8 -2
- package/dist/scheduler.d.ts +3 -1
- package/dist/scheduler.js +76 -2
- package/dist/version-metadata.json +1 -1
- package/dist/work-context-resolver.js +17 -3
- package/package.json +3 -5
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ Use an exact semver entry when you want a fixed plugin version:
|
|
|
31
31
|
|
|
32
32
|
```json
|
|
33
33
|
{
|
|
34
|
-
"plugin": ["kibi-opencode@0.
|
|
34
|
+
"plugin": ["kibi-opencode@0.18.1"]
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
|
@@ -54,9 +54,9 @@ The plugin now uses a posture-aware, low-token smart-enforcement model before em
|
|
|
54
54
|
- **Risk classification**: separates `safe_docs_only`, `safe_test_only`, `kb_doc_structural`, `req_policy_candidate`, `behavior_candidate`, `traceability_candidate`, and `manual_kb_edit`
|
|
55
55
|
- **Source-linked Kibi links**: risky code edits (`behavior_candidate`, `traceability_candidate`) prepend a concise list of existing Kibi links (e.g., `- Existing Kibi links: REQ-001, REQ-002`) when 1-3 concrete source-linked KB hits are found in `documentation/symbols.yaml`. Skip on cache hit.
|
|
56
56
|
- **Start-task risky cue**: authoritative risky edits also add a compact Kibi context cue so agents can start with explicit source-linked guidance before acting, while staying inside the same single prompt block and token budget.
|
|
57
|
-
- **Effective mode gating**: `advisory` (default) never blocks; `strict` escalates checks and reminders for `root_active` and `hybrid_root_plus_vendored` postures when `requireRootKbForStrict` is enabled; `hard` fails closed for authoritative roots and linked git worktrees, injecting
|
|
57
|
+
- **Effective mode gating**: `advisory` (default) never blocks; `strict` escalates checks and reminders for `root_active` and `hybrid_root_plus_vendored` postures when `requireRootKbForStrict` is enabled; `hard` fails closed for authoritative roots and linked git worktrees, injecting capability-based recovery steps until the Kibi checkpoint passes. `maintenanceDegraded` overrides everything back to `advisory`.
|
|
58
58
|
- **Low-token prompt policy**: docs-only and test-only edits avoid unnecessary discovery prompts; vendored-only repos suppress operational bootstrap nudges; at most one contextual block is injected per prompt (≤120 words, ≤5 bullets)
|
|
59
|
-
- **Completion reminder**: when `completionReminder` is enabled, risky code edits append a single prompt-visible `kb_check` reminder exactly once per cached context
|
|
59
|
+
- **Completion reminder**: when `completionReminder` is enabled, risky code edits append a single prompt-visible impact-enabled `kb_check` reminder exactly once per cached context
|
|
60
60
|
- **Runtime maintenance overlay**: static `maintenanceDegraded` from posture is merged with a latched runtime overlay (sync disabled/unavailable/failing) so degraded state is consistently reflected in prompts, logs, and mode decisions
|
|
61
61
|
- **Three-mode enforcement**: `advisory` by default keeps guidance non-blocking; opt-in `strict` adds elevated validation cues; `hard` blocks the prompt for authoritative workspaces until the checkpoint cycle succeeds. Git hooks and KB validation checks remain the durable enforcement boundary for all modes.
|
|
62
62
|
- **Structured observability**: posture, risk, cache, degraded-mode, targeted-check, and guidance events flow through structured plugin logs
|
|
@@ -75,11 +75,13 @@ modified, the plugin evaluates KB freshness evidence and surfaces a visible
|
|
|
75
75
|
discovery via `kb_search` or `kb_query(sourceFile=...)` and `kb_check`.
|
|
76
76
|
- **Deferred/Failed**: Do not claim task completion.
|
|
77
77
|
|
|
78
|
+
For meaningful source edits, the first gate is MCP `kb_check` with impact options, for example `kb_check({sourceFiles:["src/feature.ts"], includeImpactDiagnostics:true, includeWorkingTreeDiff:true})`. These diagnostics guide symbol granularity, requirement ownership, and semantic review of linked requirements/tests; they do not prove source behavior matches prose.
|
|
79
|
+
|
|
78
80
|
### Dynamic Contextual Guidance
|
|
79
81
|
|
|
80
82
|
The plugin provides context-aware prompt guidance based on recent edits and workspace state:
|
|
81
83
|
|
|
82
|
-
- **Code edits**: Guidance for querying Kibi by sourceFile, preferring Kibi over comments, and adding
|
|
84
|
+
- **Code edits**: Guidance for running impact-enabled `kb_check`, querying Kibi by sourceFile, preferring Kibi over comments, and adding or updating symbol traceability
|
|
83
85
|
- **Requirement edits**: Guidance for maintaining separate REQ/SCEN/TEST artifacts and avoiding embedded scenarios
|
|
84
86
|
- **KB doc edits**: Guidance for proper entity relationships and validation
|
|
85
87
|
- **Bootstrap needed**: Detection and nudges for uninitialized repos
|
|
@@ -153,13 +155,13 @@ The plugin injects guidance into OpenCode sessions to improve agent grounding. U
|
|
|
153
155
|
|
|
154
156
|
### Bootstrap Command
|
|
155
157
|
|
|
156
|
-
OpenCode exposes Kibi MCP prompts as slash commands. The \`/init-kibi\` command triggers the \`kb_autopilot_generate\` workflow to assist in retroactive bootstrap
|
|
158
|
+
OpenCode exposes Kibi MCP prompts as slash commands. The \`/init-kibi\` command triggers the \`kb_autopilot_generate\` workflow to assist in retroactive bootstrap. Agents use visible MCP tools when available, a trusted project-local CLI JSON route with `--input` when MCP is unavailable, and stop for operator action when neither interface is available.
|
|
157
159
|
|
|
158
160
|
OpenCode may show Kibi MCP tools with the configured server prefix. For example, canonical MCP names such as `kb_autopilot_generate`, `kb_upsert`, and `kb_check` can appear to agents as `kibi_kb_autopilot_generate`, `kibi_kb_upsert`, and `kibi_kb_check`. Use the visible `kibi_kb_*` identifier when OpenCode requires an exact tool name; it maps to the same MCP operation.
|
|
159
161
|
|
|
160
|
-
### Discovery-first
|
|
162
|
+
### Discovery-first capability guidance
|
|
161
163
|
|
|
162
|
-
Agent-visible guidance
|
|
164
|
+
Agent-visible guidance selects the curated public MCP surface when visible or the equivalent dedicated CLI JSON routes in a trusted workspace:
|
|
163
165
|
|
|
164
166
|
- Discovery/reporting: `kb_search`, `kb_query`, `kb_status`, `kb_find_gaps`, `kb_coverage`, `kb_graph`
|
|
165
167
|
- Mutation/validation: `kb_upsert`, `kb_delete`, `kb_check`
|
|
@@ -305,7 +307,7 @@ If you see a false "workspace needs Kibi bootstrap" warning even though your wor
|
|
|
305
307
|
|
|
306
308
|
This is a thin bridge layer per ADR-016:
|
|
307
309
|
|
|
308
|
-
- **Agent-visible guidance**:
|
|
310
|
+
- **Agent-visible guidance**: visible public MCP tools or trusted project-local CLI JSON routes (`--input`), with a blocked/operator state when neither is available
|
|
309
311
|
- **Discovery-first workflow**: Agents are guided to use `kb_search` first, then `kb_query`, then reporting tools like `kb_status`, `kb_find_gaps`, `kb_coverage`, and `kb_graph` when needed
|
|
310
312
|
- **Internal maintenance**: Background sync operations handle KB synchronization; agents do NOT run sync commands directly
|
|
311
313
|
- Does NOT own KB storage, parsing, or validation
|
|
@@ -25,6 +25,7 @@ const ADVISORY_EDIT_KINDS = new Set([
|
|
|
25
25
|
"symbol",
|
|
26
26
|
"kb",
|
|
27
27
|
]);
|
|
28
|
+
const SOURCE_IMPACT_KINDS = new Set(["code"]);
|
|
28
29
|
function normalizeCheckpointEvidence(evidence) {
|
|
29
30
|
if (typeof evidence === "boolean") {
|
|
30
31
|
return evidence;
|
|
@@ -126,6 +127,13 @@ function advisoryText(event) {
|
|
|
126
127
|
return "- New file detected. Add or update the necessary Kibi entities and traceability before completing this task.";
|
|
127
128
|
}
|
|
128
129
|
if (event.lifecycle === "edited") {
|
|
130
|
+
if (SOURCE_IMPACT_KINDS.has(event.pathKind)) {
|
|
131
|
+
const impactCheckCall = `kb_check({sourceFiles:${JSON.stringify([event.normalizedPath])}, includeImpactDiagnostics:true, includeWorkingTreeDiff:true})`;
|
|
132
|
+
return [
|
|
133
|
+
`- Edited source file detected. Run \`${impactCheckCall}\` while the edit context is fresh.`,
|
|
134
|
+
" Use the impact diagnostics to review symbol granularity, requirement ownership, and semantic review of linked requirements/tests before completing this task.",
|
|
135
|
+
].join("\n");
|
|
136
|
+
}
|
|
129
137
|
return `- Edited file detected. Review Kibi traceability for ${event.normalizedPath} before completing this task.`;
|
|
130
138
|
}
|
|
131
139
|
const ids = event.linkedEntityResult.ids;
|
|
@@ -185,7 +193,12 @@ function hardBlockText(events) {
|
|
|
185
193
|
"Changed relevant files require Kibi verification before continuing:",
|
|
186
194
|
...pathLines,
|
|
187
195
|
...evidenceNotes,
|
|
188
|
-
"
|
|
196
|
+
"Capability-based checkpoint instructions:",
|
|
197
|
+
"- If Kibi MCP tools are visible, use MCP.",
|
|
198
|
+
"- If MCP availability is unknown and a trusted local Kibi CLI is available, use its dedicated JSON routes with `--input <file|->`.",
|
|
199
|
+
"- If neither interface is available, Kibi operation is blocked; tell the operator to enable MCP or the trusted project-local CLI.",
|
|
200
|
+
"- Do not infer MCP availability from config file existence. Do not read or edit `.kb/` files directly.",
|
|
201
|
+
"- Query before mutate. Run `kb_upsert` sequentially. Run `kb_check` before completion.",
|
|
189
202
|
"- Run `kb_search` to discover impacted requirements, tests, ADRs, and facts.",
|
|
190
203
|
`- Run \`kb_query\` with \`sourceFile\` (example sourceFile: \"${representativePath}\") for each listed path.`,
|
|
191
204
|
"- Run `kb_status` if branch or snapshot freshness matters.",
|
package/dist/init-kibi-alias.js
CHANGED
|
@@ -33,7 +33,10 @@ export function buildInitKibiAlias() {
|
|
|
33
33
|
"",
|
|
34
34
|
"## Rules",
|
|
35
35
|
"- Never apply changes without a user-facing preview and approval.",
|
|
36
|
-
"-
|
|
36
|
+
"- Prefer MCP tools; CLI routes are available when MCP is unavailable.",
|
|
37
|
+
"- If MCP availability is unknown and a trusted local Kibi CLI is available, use its dedicated JSON routes with `--input <file|->`. If neither interface is available, stop and tell the operator.",
|
|
38
|
+
"- Do not infer MCP availability from config file existence. Do not read or edit `.kb/` files directly.",
|
|
39
|
+
"- Query before mutate. Run `kb_upsert` sequentially. Run `kb_check` before completion.",
|
|
37
40
|
];
|
|
38
41
|
return lines.join("\n");
|
|
39
42
|
}
|
package/dist/prompt.js
CHANGED
|
@@ -66,7 +66,7 @@ function buildBootstrapRequiredBody(capability = getInitKibiCommandCapability())
|
|
|
66
66
|
const commandBullet = capability.supported
|
|
67
67
|
? "- When the Kibi OpenCode plugin is active and native injection is supported, use `/init-kibi` as the canonical short alias; `/kibi:init-kibi:mcp` remains the namespaced MCP fallback."
|
|
68
68
|
: "- This host does not support native `/init-kibi` injection. Kibi must fail closed and does not register a fake native alias; use `/kibi:init-kibi:mcp` instead.";
|
|
69
|
-
return `
|
|
69
|
+
return `Kibi capability selection:\n1. If Kibi MCP tools are visible, use MCP.\n2. If MCP availability is unknown and a trusted local Kibi CLI is available, use its dedicated JSON routes with \`--input <file|->\`.\n3. If neither interface is available, Kibi operation is blocked; tell the operator.\nDo not infer MCP availability from config file existence. Do not read or edit \`.kb/\` files directly. Query before mutate. Run \`kb_upsert\` sequentially. Run \`kb_check\` before completion.\n\nThis repository does not appear to have Kibi initialized. Agents should:\n${commandBullet}\n- The workflow uses \`kb_autopilot_generate\` for read-only synthesis; always preview and get approval before writes.\n- Ask the operator to handle setup or repair if bootstrap is insufficient.\n- Load \`kibi-usage\` with \`kb_skills_load\` for comprehensive guidance.`;
|
|
70
70
|
}
|
|
71
71
|
function buildHardGateBlock(block) {
|
|
72
72
|
const pathLines = block.shownPaths.map((path) => `- \`${path}\``);
|
|
@@ -80,7 +80,12 @@ function buildHardGateBlock(block) {
|
|
|
80
80
|
reasonLine,
|
|
81
81
|
"Affected files:",
|
|
82
82
|
...pathLines,
|
|
83
|
-
"
|
|
83
|
+
"Capability-based recovery steps:",
|
|
84
|
+
"- If Kibi MCP tools are visible, use MCP.",
|
|
85
|
+
"- If MCP availability is unknown and a trusted local Kibi CLI is available, use its dedicated JSON routes with `--input <file|->`.",
|
|
86
|
+
"- If neither interface is available, Kibi operation is blocked; tell the operator to enable MCP or the trusted project-local CLI.",
|
|
87
|
+
"- Do not infer MCP availability from config file existence. Do not read or edit `.kb/` files directly.",
|
|
88
|
+
"- Query before mutate. Run `kb_upsert` sequentially. Run `kb_check` before completion.",
|
|
84
89
|
"- Run `kb_search` for impacted requirements, tests, ADRs, and facts.",
|
|
85
90
|
"- Run `kb_query` with `sourceFile` for each affected file.",
|
|
86
91
|
"- Run `kb_status` if branch or snapshot freshness matters.",
|
|
@@ -120,7 +125,8 @@ Production code: use \`implements\` (symbol→req) for requirement ownership. Te
|
|
|
120
125
|
- documentation/symbols.yaml refresh is required when extraction output changes; do not revert as scope creep`,
|
|
121
126
|
manual_kb_edit: `⚠️ **WARNING: Direct .kb/ edits bypass validation**
|
|
122
127
|
|
|
123
|
-
The Kibi knowledge base is managed through
|
|
128
|
+
The Kibi knowledge base is managed through visible MCP tools or trusted project-local CLI JSON routes when MCP is unavailable. Do not read or edit \`.kb/\` files directly.
|
|
129
|
+
- Query before mutate and run kb_upsert sequentially
|
|
124
130
|
- Use kb_upsert to create/update entities
|
|
125
131
|
- Use kb_delete to remove entities
|
|
126
132
|
- Use kb_check to validate consistency`,
|
|
@@ -292,8 +298,10 @@ If you're adding long explanatory comments, consider routing that knowledge to:
|
|
|
292
298
|
}
|
|
293
299
|
}
|
|
294
300
|
}
|
|
295
|
-
catch {
|
|
296
|
-
|
|
301
|
+
catch (error) {
|
|
302
|
+
if (!(error instanceof Error)) {
|
|
303
|
+
throw error;
|
|
304
|
+
}
|
|
297
305
|
}
|
|
298
306
|
}
|
|
299
307
|
// ── File-operation reminder folding ─────────────────────────────────
|
|
@@ -471,13 +479,17 @@ Before implementing or explaining code:
|
|
|
471
479
|
*/
|
|
472
480
|
function buildBaseGuidance(capability = getInitKibiCommandCapability()) {
|
|
473
481
|
return `${SENTINEL}
|
|
474
|
-
This project uses Kibi
|
|
482
|
+
This project uses Kibi through capability-selected MCP or CLI JSON routes. Prefer storing durable knowledge in Kibi over code comments.
|
|
475
483
|
|
|
476
484
|
Before changing behavior: use kb_search for discovery, then kb_query by sourceFile, id, type, or tags for exact follow-up; do not rely on undocumented tools.
|
|
477
485
|
|
|
478
486
|
Keep changed symbols traceable: production code uses \`implements\` (symbol→req) for ownership; test code uses \`executable_for\`; \`covered_by\` is coverage evidence only. Inline \`// implements REQ-xxx\` comments remain backward-compatible.
|
|
479
487
|
|
|
480
|
-
|
|
488
|
+
Kibi capability selection:
|
|
489
|
+
1. If Kibi MCP tools are visible, use MCP.
|
|
490
|
+
2. If MCP availability is unknown and a trusted local Kibi CLI is available, use its dedicated JSON routes with \`--input <file|->\`.
|
|
491
|
+
3. If neither interface is available, Kibi operation is blocked; tell the operator to enable MCP or the trusted project-local CLI.
|
|
492
|
+
Do not infer MCP availability from config file existence. Do not read or edit \`.kb/\` files directly. Query before mutate. Run \`kb_upsert\` sequentially. Run \`kb_check\` before completion.
|
|
481
493
|
|
|
482
494
|
Dogfood note for this repo: OpenCode here uses local built \`kibi-mcp\` and \`kibi-opencode\` artifacts. If you change package versions or local package wiring, run \`bun run build\` before relying on OpenCode in this workspace.
|
|
483
495
|
|
|
@@ -490,12 +502,10 @@ Dogfood note for this repo: OpenCode here uses local built \`kibi-mcp\` and \`ki
|
|
|
490
502
|
6. **Validate**: Run kb_check after KB mutations to catch violations early.
|
|
491
503
|
7. **Before completion/commit**: Kibi impact evidence is required before completion/commit. If extraction output changes, refresh documentation/symbols.yaml and do not revert that update as scope creep.
|
|
492
504
|
|
|
493
|
-
|
|
505
|
+
MCP and CLI expose the same 18 Kibi operations. Use the exact MCP tool or dedicated CLI route; do not invent a generic runner.
|
|
494
506
|
|
|
495
507
|
For comprehensive Kibi usage guidance (relationships, fact lanes, workflows), use \`kb_skills_load\` with skill id \`kibi-usage\`.
|
|
496
508
|
|
|
497
|
-
Do not invoke Kibi CLI commands directly from the agent.
|
|
498
|
-
|
|
499
509
|
${buildInitKibiBootstrapReference(capability)}`;
|
|
500
510
|
}
|
|
501
511
|
/**
|
package/dist/repo-posture.js
CHANGED
|
@@ -111,7 +111,10 @@ function hasRootKibiIntent(cwd) {
|
|
|
111
111
|
return true;
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
|
-
catch {
|
|
114
|
+
catch (error) {
|
|
115
|
+
if (!(error instanceof Error))
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
115
118
|
for (const guidanceFile of [
|
|
116
119
|
"AGENTS.md",
|
|
117
120
|
join(".github", "copilot-instructions.md"),
|
|
@@ -122,7 +125,10 @@ function hasRootKibiIntent(cwd) {
|
|
|
122
125
|
return true;
|
|
123
126
|
}
|
|
124
127
|
}
|
|
125
|
-
catch {
|
|
128
|
+
catch (error) {
|
|
129
|
+
if (!(error instanceof Error))
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
126
132
|
}
|
|
127
133
|
return false;
|
|
128
134
|
}
|
package/dist/scheduler.d.ts
CHANGED
|
@@ -24,7 +24,9 @@ export type SyncRunnerResult = {
|
|
|
24
24
|
};
|
|
25
25
|
export type SyncRunner = (worktree: string) => Promise<SyncRunnerResult>;
|
|
26
26
|
export type CheckRunner = (worktree: string, rules: string[]) => Promise<{
|
|
27
|
-
exitCode: number;
|
|
27
|
+
readonly exitCode: number;
|
|
28
|
+
readonly stdout?: string;
|
|
29
|
+
readonly stderr?: string;
|
|
28
30
|
}>;
|
|
29
31
|
export interface SchedulerOptions {
|
|
30
32
|
worktree: string;
|
package/dist/scheduler.js
CHANGED
|
@@ -154,6 +154,7 @@ class WorktreeSyncScheduler {
|
|
|
154
154
|
}
|
|
155
155
|
else {
|
|
156
156
|
logger.info(`check.succeeded ${JSON.stringify({ rules: checkRules })}`);
|
|
157
|
+
logAdvisoryQualityDiagnostics(checkRules, checkResult.stdout, checkResult.stderr);
|
|
157
158
|
}
|
|
158
159
|
}
|
|
159
160
|
}
|
|
@@ -280,11 +281,84 @@ async function runKibiSync(worktree) {
|
|
|
280
281
|
async function runKibiCheck(worktree, rules) {
|
|
281
282
|
return new Promise((resolve) => {
|
|
282
283
|
const rulesArg = rules.join(",");
|
|
283
|
-
exec(`kibi check --rules ${rulesArg}`, { cwd: worktree }, (error) => {
|
|
284
|
-
|
|
284
|
+
exec(`kibi check --rules ${rulesArg} --format json`, { cwd: worktree }, (error, stdout, stderr) => {
|
|
285
|
+
const truncatedOut = truncateSyncOutput(stdout || undefined);
|
|
286
|
+
const truncatedErr = truncateSyncOutput(stderr || undefined);
|
|
287
|
+
resolve({
|
|
288
|
+
exitCode: error ? (error.code ?? 1) : 0,
|
|
289
|
+
...(truncatedOut !== undefined ? { stdout: truncatedOut } : {}),
|
|
290
|
+
...(truncatedErr !== undefined ? { stderr: truncatedErr } : {}),
|
|
291
|
+
});
|
|
285
292
|
});
|
|
286
293
|
});
|
|
287
294
|
}
|
|
295
|
+
function logAdvisoryQualityDiagnostics(rules, stdout, stderr) {
|
|
296
|
+
const diagnostics = parseQualityDiagnostics(stdout, stderr).filter((diagnostic) => !diagnostic.blocking);
|
|
297
|
+
if (diagnostics.length === 0)
|
|
298
|
+
return;
|
|
299
|
+
const severityCounts = new Map();
|
|
300
|
+
for (const diagnostic of diagnostics) {
|
|
301
|
+
severityCounts.set(diagnostic.severity, (severityCounts.get(diagnostic.severity) ?? 0) + 1);
|
|
302
|
+
}
|
|
303
|
+
const first = diagnostics[0];
|
|
304
|
+
if (first === undefined)
|
|
305
|
+
return;
|
|
306
|
+
logger.warn(`check.advisory_quality ${JSON.stringify({
|
|
307
|
+
rules,
|
|
308
|
+
count: diagnostics.length,
|
|
309
|
+
...Object.fromEntries(severityCounts),
|
|
310
|
+
firstId: first.id,
|
|
311
|
+
firstMessage: first.message,
|
|
312
|
+
})}`);
|
|
313
|
+
}
|
|
314
|
+
function parseQualityDiagnostics(stdout, stderr) {
|
|
315
|
+
for (const output of [stdout, stderr]) {
|
|
316
|
+
if (output === undefined || output.trim().length === 0)
|
|
317
|
+
continue;
|
|
318
|
+
try {
|
|
319
|
+
const parsed = JSON.parse(output);
|
|
320
|
+
const candidates = qualityDiagnosticCandidates(parsed);
|
|
321
|
+
const diagnostics = candidates.flatMap((candidate) => parseQualityDiagnostic(candidate) ?? []);
|
|
322
|
+
if (diagnostics.length > 0)
|
|
323
|
+
return diagnostics;
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
if (error instanceof SyntaxError)
|
|
327
|
+
continue;
|
|
328
|
+
throw error;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return [];
|
|
332
|
+
}
|
|
333
|
+
function qualityDiagnosticCandidates(value) {
|
|
334
|
+
if (!isRecord(value))
|
|
335
|
+
return [];
|
|
336
|
+
const structuredContent = value.structuredContent;
|
|
337
|
+
if (isRecord(structuredContent)) {
|
|
338
|
+
const diagnostics = structuredContent.qualityDiagnostics;
|
|
339
|
+
return Array.isArray(diagnostics) ? diagnostics : [];
|
|
340
|
+
}
|
|
341
|
+
const diagnostics = value.qualityDiagnostics;
|
|
342
|
+
return Array.isArray(diagnostics) ? diagnostics : [];
|
|
343
|
+
}
|
|
344
|
+
function parseQualityDiagnostic(value) {
|
|
345
|
+
if (!isRecord(value))
|
|
346
|
+
return null;
|
|
347
|
+
const id = value.id;
|
|
348
|
+
const severity = value.severity;
|
|
349
|
+
const blocking = value.blocking;
|
|
350
|
+
const message = value.message;
|
|
351
|
+
if (typeof id !== "string" ||
|
|
352
|
+
typeof severity !== "string" ||
|
|
353
|
+
typeof blocking !== "boolean" ||
|
|
354
|
+
typeof message !== "string") {
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
return { id, severity, blocking, message };
|
|
358
|
+
}
|
|
359
|
+
function isRecord(value) {
|
|
360
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
361
|
+
}
|
|
288
362
|
// implements REQ-opencode-kibi-plugin-v1
|
|
289
363
|
export function createSyncScheduler(opts) {
|
|
290
364
|
return new WorktreeSyncScheduler(opts);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"opencode":"0.
|
|
1
|
+
{"opencode":"0.19.1","mcp":"0.19.2","cli":"0.16.1","core":"0.7.1"}
|
|
@@ -46,8 +46,9 @@ function directorySearchStart(candidatePath) {
|
|
|
46
46
|
const stats = safeStat(resolved);
|
|
47
47
|
return stats?.isDirectory() ? resolved : dirname(resolved);
|
|
48
48
|
}
|
|
49
|
-
function findGitMetadata(candidatePath) {
|
|
49
|
+
function findGitMetadata(candidatePath, searchBoundary) {
|
|
50
50
|
let current = directorySearchStart(candidatePath);
|
|
51
|
+
const boundary = searchBoundary ? resolve(searchBoundary) : null;
|
|
51
52
|
while (true) {
|
|
52
53
|
const dotGitPath = join(current, ".git");
|
|
53
54
|
const dotGitStats = safeStat(dotGitPath);
|
|
@@ -70,6 +71,9 @@ function findGitMetadata(candidatePath) {
|
|
|
70
71
|
isLinkedWorktree: false,
|
|
71
72
|
};
|
|
72
73
|
}
|
|
74
|
+
if (boundary !== null && current === boundary) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
73
77
|
const parent = dirname(current);
|
|
74
78
|
if (parent === current) {
|
|
75
79
|
return null;
|
|
@@ -174,8 +178,18 @@ const resolveWorkContext = function resolveWorkContext(input) {
|
|
|
174
178
|
? resolve(input.filePath)
|
|
175
179
|
: resolve(declaredWorktreeRoot, input.filePath)
|
|
176
180
|
: undefined;
|
|
177
|
-
const
|
|
178
|
-
|
|
181
|
+
const fileRelativeToDeclaredRoot = absoluteFilePath
|
|
182
|
+
? relative(declaredWorktreeRoot, absoluteFilePath)
|
|
183
|
+
: null;
|
|
184
|
+
const fileSearchBoundary = fileRelativeToDeclaredRoot !== null &&
|
|
185
|
+
!fileRelativeToDeclaredRoot.startsWith(`..${sep}`) &&
|
|
186
|
+
fileRelativeToDeclaredRoot !== ".." &&
|
|
187
|
+
!isAbsolute(fileRelativeToDeclaredRoot)
|
|
188
|
+
? declaredWorktreeRoot
|
|
189
|
+
: undefined;
|
|
190
|
+
const git = (absoluteFilePath
|
|
191
|
+
? findGitMetadata(absoluteFilePath, fileSearchBoundary)
|
|
192
|
+
: null) ?? findGitMetadata(declaredWorktreeRoot, declaredWorktreeRoot);
|
|
179
193
|
const worktreeRoot = git?.worktreeRoot ?? declaredWorktreeRoot;
|
|
180
194
|
const kibiAuthorityRoot = git
|
|
181
195
|
? resolveAuthorityRoot(git, declaredDirectory)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kibi-opencode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"description": "Kibi OpenCode plugin - thin adapter to integrate Kibi with OpenCode sessions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -37,9 +37,7 @@
|
|
|
37
37
|
"default": "./dist/tui.js"
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
|
-
"files": [
|
|
41
|
-
"dist"
|
|
42
|
-
],
|
|
40
|
+
"files": ["dist"],
|
|
43
41
|
"engines": {
|
|
44
42
|
"node": ">=18"
|
|
45
43
|
},
|
|
@@ -62,7 +60,7 @@
|
|
|
62
60
|
"@opencode-ai/plugin": "^1.4.7",
|
|
63
61
|
"@opentui/core": "^0.1.99",
|
|
64
62
|
"@opentui/solid": "^0.1.99",
|
|
65
|
-
"kibi-cli": "^0.
|
|
63
|
+
"kibi-cli": "^0.16.0"
|
|
66
64
|
},
|
|
67
65
|
"devDependencies": {
|
|
68
66
|
"@types/node": "latest",
|