kibi-agent-core 0.8.0 → 0.9.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/CHANGELOG.md +19 -0
- package/dist/decision-guard.d.ts +16 -1
- package/dist/decision-guard.js +54 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# kibi-agent-core
|
|
2
2
|
|
|
3
|
+
## 0.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 180196c: The requirements signoff view now reads well on every host, not only in the hosts that draw Kibi's fenced block.
|
|
8
|
+
- `kibi signoff` prints plain Markdown by default (`--format chat`): headings, quoted statements and lists that render in any chat window, and in messaging tools for agents whose replies go through one (cloud and project sessions). The path of the self-contained page `.kb/briefs/signoff/latest.html` goes to stderr, so an agent can attach or publish it next to the message. `--format md` keeps the fenced block for the OpenCode terminal card, and `KIBI_SIGNOFF_FORMAT` sets the default per host.
|
|
9
|
+
- After a session writes a requirement, the Claude Code, Codex, Cursor and ZCode stop hooks ask once for the signoff view before the work is reported done, unless `kibi signoff` already ran since. A requirement the agent wrote is put to the person through the view, not retold in the agent's words.
|
|
10
|
+
- `/kibi-signoff` is a new command in Claude Code, Cursor and ZCode.
|
|
11
|
+
- The `kibi-decisions` and `kibi-commit-review` skills (1.2.0) say how to show the view on each host, and `kibi-usage` (2.22.0) points to `kibi signoff` when it says to leave `approved_by` to the person. The OpenCode guidance asks for `--format md` so the terminal card still renders.
|
|
12
|
+
- The Claude Code plugin README shows the `.claude/settings.json` snippet that loads the plugin in cloud sessions.
|
|
13
|
+
|
|
14
|
+
## 0.8.1
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- f4c5822: After a migration, the `kb_apply_plan` digest of the remaining plan now says when an automatic action in it is blocked: it waits for the actions in its `dependsOn` and needs no approval until a later plan shows it ready. Before, a blocked automatic action looked like something left to approve. The Claude hook's firm-edit question no longer prints a double full stop after a requirement title that ends in one.
|
|
19
|
+
|
|
20
|
+
The digest's `next` text appends a count of blocked automatic actions when there are any. `firmEditConfirmation` in `kibi-agent-core/decision-guard` trims a trailing full stop from the named requirements before closing the sentence.
|
|
21
|
+
|
|
3
22
|
## 0.8.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
package/dist/decision-guard.d.ts
CHANGED
|
@@ -55,7 +55,7 @@ export type DecisionSession = {
|
|
|
55
55
|
sessionId: string | undefined;
|
|
56
56
|
};
|
|
57
57
|
/** Session markers the decision guard keeps. */
|
|
58
|
-
export type DecisionFlag = "source-edited" | "kb-recorded" | "rule-prompt" | "capture-asked";
|
|
58
|
+
export type DecisionFlag = "source-edited" | "kb-recorded" | "rule-prompt" | "capture-asked" | "requirement-recorded" | "signoff-asked";
|
|
59
59
|
/** Set a session marker; best effort. */
|
|
60
60
|
export declare function markDecisionFlag(session: DecisionSession, flag: DecisionFlag): void;
|
|
61
61
|
export declare function hasDecisionFlag(session: DecisionSession, flag: DecisionFlag): boolean;
|
|
@@ -77,6 +77,21 @@ export declare function requestWords(session: DecisionSession): string[];
|
|
|
77
77
|
* not been asked yet (claiming the ask).
|
|
78
78
|
*/
|
|
79
79
|
export declare function claimCaptureReminder(session: DecisionSession): boolean;
|
|
80
|
+
/** Where `kibi signoff` keeps the latest view, relative to the workspace. */
|
|
81
|
+
export declare const SIGNOFF_LATEST_JSON: string;
|
|
82
|
+
/**
|
|
83
|
+
* Whether a kb_upsert call's input writes a requirement (not a dry run).
|
|
84
|
+
* Hosts pass the MCP arguments, sometimes wrapped in `arguments`.
|
|
85
|
+
*/
|
|
86
|
+
export declare function isRequirementUpsert(toolInput: unknown): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Whether the stop should ask for a signoff view: the session wrote a
|
|
89
|
+
* requirement, `kibi signoff` has not written a view since, and the session
|
|
90
|
+
* has not been asked yet (claiming the ask).
|
|
91
|
+
*/
|
|
92
|
+
export declare function claimSignoffReminder(session: DecisionSession, workspaceRoot: string): boolean;
|
|
93
|
+
/** Stop-time note for a session that recorded requirements without a signoff view. */
|
|
94
|
+
export declare function signoffReminder(): string;
|
|
80
95
|
/** Firm requirements the agent was already told about this session. */
|
|
81
96
|
export declare function settledFirmRequirements(session: DecisionSession): Set<string>;
|
|
82
97
|
/** Remember that the agent was told about these firm requirements. */
|
package/dist/decision-guard.js
CHANGED
|
@@ -52,7 +52,9 @@ export function firmEditConfirmation(where, requirements) {
|
|
|
52
52
|
? ` (+${requirements.length - shown.length} more)`
|
|
53
53
|
: "";
|
|
54
54
|
const noun = requirements.length === 1 ? "a firm requirement" : "firm requirements";
|
|
55
|
-
|
|
55
|
+
// A title that ends in a full stop would read "preference.. Allow".
|
|
56
|
+
const named = `${shown.join("; ")}${more}`.replace(/\.+$/, "");
|
|
57
|
+
return `Kibi: this edit changes ${where}, which implements ${noun} recorded in the knowledge base: ${named}. Allow it if the change keeps ${requirements.length === 1 ? "that requirement" : "them"}, or if you mean to change ${requirements.length === 1 ? "the requirement" : "them"} too.`;
|
|
56
58
|
}
|
|
57
59
|
// implements REQ-claude-firm-edit-confirmation
|
|
58
60
|
/** What the agent is told when its edit was put to the person. */
|
|
@@ -210,6 +212,57 @@ export function claimCaptureReminder(session) {
|
|
|
210
212
|
!hasDecisionFlag(session, "kb-recorded") &&
|
|
211
213
|
claimDecisionFlag(session, "capture-asked"));
|
|
212
214
|
}
|
|
215
|
+
// implements REQ-kibi-signoff-views
|
|
216
|
+
/** Where `kibi signoff` keeps the latest view, relative to the workspace. */
|
|
217
|
+
export const SIGNOFF_LATEST_JSON = path.join(".kb", "briefs", "signoff", "latest.json");
|
|
218
|
+
function record(value) {
|
|
219
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
220
|
+
? value
|
|
221
|
+
: undefined;
|
|
222
|
+
}
|
|
223
|
+
// implements REQ-kibi-signoff-views
|
|
224
|
+
/**
|
|
225
|
+
* Whether a kb_upsert call's input writes a requirement (not a dry run).
|
|
226
|
+
* Hosts pass the MCP arguments, sometimes wrapped in `arguments`.
|
|
227
|
+
*/
|
|
228
|
+
export function isRequirementUpsert(toolInput) {
|
|
229
|
+
const input = record(toolInput);
|
|
230
|
+
const args = record(input?.arguments) ?? record(input?.args) ?? input;
|
|
231
|
+
return args?.type === "req" && args.dryRun !== true;
|
|
232
|
+
}
|
|
233
|
+
function mtimeMs(file) {
|
|
234
|
+
if (!file)
|
|
235
|
+
return undefined;
|
|
236
|
+
try {
|
|
237
|
+
return fs.statSync(file).mtimeMs;
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
return undefined;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
// implements REQ-kibi-signoff-views
|
|
244
|
+
/**
|
|
245
|
+
* Whether the stop should ask for a signoff view: the session wrote a
|
|
246
|
+
* requirement, `kibi signoff` has not written a view since, and the session
|
|
247
|
+
* has not been asked yet (claiming the ask).
|
|
248
|
+
*/
|
|
249
|
+
export function claimSignoffReminder(session, workspaceRoot) {
|
|
250
|
+
const recorded = mtimeMs(sessionPath(session, "requirement-recorded"));
|
|
251
|
+
if (recorded === undefined)
|
|
252
|
+
return false;
|
|
253
|
+
const shown = mtimeMs(path.join(workspaceRoot, SIGNOFF_LATEST_JSON));
|
|
254
|
+
if (shown !== undefined && shown >= recorded)
|
|
255
|
+
return false;
|
|
256
|
+
return claimDecisionFlag(session, "signoff-asked");
|
|
257
|
+
}
|
|
258
|
+
// implements REQ-kibi-signoff-views
|
|
259
|
+
/** Stop-time note for a session that recorded requirements without a signoff view. */
|
|
260
|
+
export function signoffReminder() {
|
|
261
|
+
return [
|
|
262
|
+
"Kibi: this session recorded or changed requirements, and the person has not seen them as a signoff view.",
|
|
263
|
+
"Before reporting the work done or asking to commit, run `kibi signoff` and put its output in the reply unchanged; a requirement the agent wrote waits for the person's approval, so ask for it with this view, never in your own words. When replies go through a messaging tool, pass the output there, and attach or publish `.kb/briefs/signoff/latest.html` when the host can show a page (kibi-decisions, resources/signoff-views.md).",
|
|
264
|
+
].join("\n");
|
|
265
|
+
}
|
|
213
266
|
function readSettled(file) {
|
|
214
267
|
if (!file)
|
|
215
268
|
return [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kibi-agent-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Shared low-latency hook helpers for Kibi agent adapters",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -66,6 +66,6 @@
|
|
|
66
66
|
"@types/node": "^25.9.8",
|
|
67
67
|
"semver": "^7.8.5",
|
|
68
68
|
"typescript": "^5.7.0",
|
|
69
|
-
"yaml": "^2.9.
|
|
69
|
+
"yaml": "^2.9.1"
|
|
70
70
|
}
|
|
71
71
|
}
|