kimi-plugin-cc 2.0.8 → 2.2.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +27 -0
- package/README.md +5 -5
- package/agents/kimi-ask.md +5 -1
- package/agents/kimi-challenge.md +4 -2
- package/agents/kimi-pursue.md +3 -1
- package/agents/kimi-rescue.md +5 -1
- package/agents/kimi-review.md +4 -2
- package/agents/kimi-swarm-write.md +3 -1
- package/agents/kimi-swarm.md +3 -1
- package/commands/ask.md +5 -3
- package/commands/challenge.md +5 -3
- package/commands/pursue.md +5 -1
- package/commands/rescue.md +5 -3
- package/commands/review.md +5 -3
- package/commands/swarm.md +5 -1
- package/dist/cli-client.js +42 -10
- package/dist/commands/ask.js +14 -7
- package/dist/commands/cli-helpers.js +66 -4
- package/dist/commands/pursue.js +7 -3
- package/dist/commands/rescue.js +16 -10
- package/dist/commands/result.js +5 -1
- package/dist/commands/review-gate.js +21 -14
- package/dist/commands/review.js +9 -5
- package/dist/commands/status.js +2 -2
- package/dist/commands/swarm.js +10 -4
- package/dist/help.js +1 -1
- package/dist/hook-escape.js +71 -0
- package/dist/hooks/approval-policy.js +17 -27
- package/dist/hooks/config-safety.js +15 -7
- package/dist/job-store.js +52 -7
- package/dist/kimi-engine.js +2 -0
- package/dist/kimi-errors.js +1 -1
- package/dist/kimi-timeouts.js +6 -10
- package/dist/kimi-version-probe.js +2 -2
- package/dist/parsing.js +59 -53
- package/dist/session-recovery.js +203 -0
- package/dist/vendor/smol-toml/date.js +50 -21
- package/dist/vendor/smol-toml/error.js +6 -2
- package/dist/vendor/smol-toml/extract.js +259 -66
- package/dist/vendor/smol-toml/parse.js +64 -48
- package/dist/vendor/smol-toml/primitive.js +107 -135
- package/dist/vendor/smol-toml/struct.js +106 -134
- package/dist/vendor/smol-toml/util.js +22 -78
- package/dist/version.js +1 -1
- package/docs/models.md +10 -0
- package/docs/registry-releases.md +24 -1
- package/docs/safety.md +59 -2
- package/package.json +1 -1
- package/plugins/kimi-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/kimi-codex/dist/cli-client.js +42 -10
- package/plugins/kimi-codex/dist/commands/ask.js +14 -7
- package/plugins/kimi-codex/dist/commands/cli-helpers.js +66 -4
- package/plugins/kimi-codex/dist/commands/pursue.js +7 -3
- package/plugins/kimi-codex/dist/commands/rescue.js +16 -10
- package/plugins/kimi-codex/dist/commands/result.js +5 -1
- package/plugins/kimi-codex/dist/commands/review-gate.js +21 -14
- package/plugins/kimi-codex/dist/commands/review.js +9 -5
- package/plugins/kimi-codex/dist/commands/status.js +2 -2
- package/plugins/kimi-codex/dist/commands/swarm.js +10 -4
- package/plugins/kimi-codex/dist/help.js +1 -1
- package/plugins/kimi-codex/dist/hook-escape.js +71 -0
- package/plugins/kimi-codex/dist/hooks/approval-policy.js +17 -27
- package/plugins/kimi-codex/dist/hooks/config-safety.js +15 -7
- package/plugins/kimi-codex/dist/job-store.js +52 -7
- package/plugins/kimi-codex/dist/kimi-engine.js +2 -0
- package/plugins/kimi-codex/dist/kimi-errors.js +1 -1
- package/plugins/kimi-codex/dist/kimi-timeouts.js +6 -10
- package/plugins/kimi-codex/dist/kimi-version-probe.js +2 -2
- package/plugins/kimi-codex/dist/parsing.js +59 -53
- package/plugins/kimi-codex/dist/session-recovery.js +203 -0
- package/plugins/kimi-codex/dist/vendor/smol-toml/date.js +50 -21
- package/plugins/kimi-codex/dist/vendor/smol-toml/error.js +6 -2
- package/plugins/kimi-codex/dist/vendor/smol-toml/extract.js +259 -66
- package/plugins/kimi-codex/dist/vendor/smol-toml/parse.js +64 -48
- package/plugins/kimi-codex/dist/vendor/smol-toml/primitive.js +107 -135
- package/plugins/kimi-codex/dist/vendor/smol-toml/struct.js +106 -134
- package/plugins/kimi-codex/dist/vendor/smol-toml/util.js +22 -78
- package/plugins/kimi-codex/dist/version.js +1 -1
- package/plugins/kimi-codex/skills/kimi-ask/SKILL.md +4 -2
- package/plugins/kimi-codex/skills/kimi-challenge/SKILL.md +4 -2
- package/plugins/kimi-codex/skills/kimi-pursue/SKILL.md +3 -1
- package/plugins/kimi-codex/skills/kimi-rescue/SKILL.md +4 -2
- package/plugins/kimi-codex/skills/kimi-review/SKILL.md +4 -2
- package/plugins/kimi-codex/skills/kimi-setup/SKILL.md +2 -0
- package/plugins/kimi-codex/skills/kimi-swarm/SKILL.md +3 -1
- package/plugins/kimi-codex/skills/kimi-swarm-write/SKILL.md +3 -1
|
@@ -27,158 +27,130 @@
|
|
|
27
27
|
*/
|
|
28
28
|
import { parseString } from './primitive.js';
|
|
29
29
|
import { extractValue } from './extract.js';
|
|
30
|
-
import {
|
|
30
|
+
import { skipVoid } from './util.js';
|
|
31
31
|
import { TomlError } from './error.js';
|
|
32
|
-
|
|
33
|
-
export function parseKey(
|
|
34
|
-
|
|
32
|
+
/** @internal */
|
|
33
|
+
export function parseKey(ctx, end = 0x3d /* = */) {
|
|
34
|
+
// States:
|
|
35
|
+
// 0: before first char
|
|
36
|
+
// 1: parsing bare key
|
|
37
|
+
// 2: after key component
|
|
38
|
+
let startPtr;
|
|
39
|
+
let state = 0;
|
|
35
40
|
let parsed = [];
|
|
36
|
-
let
|
|
37
|
-
|
|
38
|
-
throw new TomlError('incomplete key-value: cannot find end of key', {
|
|
39
|
-
toml: str,
|
|
40
|
-
ptr: ptr,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
41
|
+
let sliceStart;
|
|
42
|
+
let c = ctx.s.charCodeAt(startPtr = ctx.p);
|
|
43
43
|
do {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
toml: str,
|
|
74
|
-
ptr: eos,
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
if (endPtr < eos) {
|
|
78
|
-
endPtr = str.indexOf(end, eos);
|
|
79
|
-
if (endPtr < 0) {
|
|
80
|
-
throw new TomlError('incomplete key-value: cannot find end of key', {
|
|
81
|
-
toml: str,
|
|
82
|
-
ptr: ptr,
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
parsed.push(parseString(str, ptr, eos));
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
// Normal raw key part consumption and validation
|
|
90
|
-
dot = str.indexOf('.', ptr);
|
|
91
|
-
let part = str.slice(ptr, dot < 0 || dot > endPtr ? endPtr : dot);
|
|
92
|
-
if (!KEY_PART_RE.test(part)) {
|
|
93
|
-
throw new TomlError('only letter, numbers, dashes and underscores are allowed in keys', {
|
|
94
|
-
toml: str,
|
|
95
|
-
ptr: ptr,
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
parsed.push(part.trimEnd());
|
|
44
|
+
// End of key
|
|
45
|
+
if (c === end) {
|
|
46
|
+
if (!state)
|
|
47
|
+
TomlError.x('unexpected end of key', ctx);
|
|
48
|
+
if (state === 1)
|
|
49
|
+
parsed.push(ctx.s.slice(sliceStart, ctx.p));
|
|
50
|
+
return ctx.p++, parsed;
|
|
51
|
+
}
|
|
52
|
+
// Dotted key separator
|
|
53
|
+
else if (c === 0x2e /* . */) {
|
|
54
|
+
if (!state)
|
|
55
|
+
TomlError.x('illegal empty bare key', ctx);
|
|
56
|
+
if (state === 1)
|
|
57
|
+
parsed.push(ctx.s.slice(sliceStart, ctx.p));
|
|
58
|
+
state = 0;
|
|
59
|
+
}
|
|
60
|
+
// Quoted key
|
|
61
|
+
else if (!state && (c === 0x22 /* " */ || c === 0x27 /* ' */)) {
|
|
62
|
+
if (c === ctx.s.charCodeAt(ctx.p + 1) && c === ctx.s.charCodeAt(ctx.p + 2))
|
|
63
|
+
TomlError.x('illegal quoted key: multiline strings are not allowed', ctx);
|
|
64
|
+
parsed.push(parseString(ctx));
|
|
65
|
+
state = 2;
|
|
66
|
+
ctx.p--;
|
|
67
|
+
}
|
|
68
|
+
// Whitespace; no-op in state 0 and 2, end of bare key in state 1
|
|
69
|
+
else if (c === 0x20 || c === 0x9 /* \t */) {
|
|
70
|
+
if (state === 1) {
|
|
71
|
+
parsed.push(ctx.s.slice(sliceStart, ctx.p));
|
|
72
|
+
state = 2;
|
|
99
73
|
}
|
|
100
74
|
}
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
75
|
+
// If state is post-key, no character is allowed; otherwise ensure it's a bare-key component
|
|
76
|
+
else if (state === 2 || (c < 0x30 && c !== 0x2d /* - */) || (c > 0x39 && c < 0x41) || (c > 0x5a && c < 0x61 && c !== 0x5f /* _ */) || c > 0x7a) {
|
|
77
|
+
TomlError.x('illegal character in key', ctx);
|
|
78
|
+
}
|
|
79
|
+
// Illegal character
|
|
80
|
+
else if (!state) {
|
|
81
|
+
state = 1;
|
|
82
|
+
sliceStart = ctx.p;
|
|
83
|
+
}
|
|
84
|
+
} while (c = ctx.s.charCodeAt(++ctx.p));
|
|
85
|
+
TomlError.x('incomplete key-value: cannot find end of key', ctx, startPtr);
|
|
104
86
|
}
|
|
105
|
-
|
|
106
|
-
|
|
87
|
+
/** @internal */
|
|
88
|
+
export function parseInlineTable(ctx) {
|
|
89
|
+
let startPtr = ctx.p++;
|
|
90
|
+
let res = Object.create(null);
|
|
107
91
|
let seen = new Set();
|
|
108
92
|
let c;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (c ===
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
ptr: ptr - 1,
|
|
115
|
-
});
|
|
93
|
+
while (ctx.p < ctx.s.length) {
|
|
94
|
+
skipVoid(ctx);
|
|
95
|
+
if ((c = ctx.s.charCodeAt(ctx.p)) === 0x7d /* } */) {
|
|
96
|
+
ctx.p++;
|
|
97
|
+
return res;
|
|
116
98
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
if (!hasOwn && k === '__proto__') {
|
|
135
|
-
Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
|
|
136
|
-
}
|
|
99
|
+
let k;
|
|
100
|
+
let t = res;
|
|
101
|
+
let hasOwn = false;
|
|
102
|
+
let errPtr = ctx.p;
|
|
103
|
+
let key = parseKey(ctx);
|
|
104
|
+
for (let i = 0; i < key.length; i++) {
|
|
105
|
+
if (i)
|
|
106
|
+
t = hasOwn ? t[k] : (t[k] = Object.create(null));
|
|
107
|
+
k = key[i];
|
|
108
|
+
if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== 'object' || seen.has(t[k]))) {
|
|
109
|
+
TomlError.x('trying to redefine an already defined value', ctx, errPtr);
|
|
110
|
+
}
|
|
111
|
+
let unsafe = k === '__proto__';
|
|
112
|
+
if (ctx.uk && (unsafe || k === 'constructor')) {
|
|
113
|
+
t = ctx.uk !== 1 && TomlError.x('document contains an unsafe property', ctx, errPtr);
|
|
114
|
+
break;
|
|
137
115
|
}
|
|
138
|
-
if (hasOwn) {
|
|
139
|
-
|
|
140
|
-
toml: str,
|
|
141
|
-
ptr: ptr,
|
|
142
|
-
});
|
|
116
|
+
if (!hasOwn && unsafe) {
|
|
117
|
+
Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
|
|
143
118
|
}
|
|
144
|
-
|
|
119
|
+
}
|
|
120
|
+
if (hasOwn) {
|
|
121
|
+
TomlError.x('trying to redefine an already defined value', ctx, errPtr);
|
|
122
|
+
}
|
|
123
|
+
skipVoid(ctx, true, true);
|
|
124
|
+
let value = extractValue(ctx, 0x7d /* } */);
|
|
125
|
+
if (t && typeof (t[k] = value) === 'object')
|
|
145
126
|
seen.add(value);
|
|
146
|
-
|
|
147
|
-
|
|
127
|
+
skipVoid(ctx);
|
|
128
|
+
if ((c = ctx.s.charCodeAt(ctx.p++)) === 0x7d /* } */) {
|
|
129
|
+
return res;
|
|
148
130
|
}
|
|
131
|
+
if (c !== 0x2c /* , */)
|
|
132
|
+
TomlError.x('expected comma or end of structure', ctx, ctx.p - 1);
|
|
149
133
|
}
|
|
150
|
-
|
|
151
|
-
throw new TomlError('unfinished table encountered', {
|
|
152
|
-
toml: str,
|
|
153
|
-
ptr: ptr,
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
return [res, ptr];
|
|
134
|
+
TomlError.x('unfinished table', ctx, startPtr);
|
|
157
135
|
}
|
|
158
|
-
|
|
136
|
+
/** @internal */
|
|
137
|
+
export function parseArray(ctx) {
|
|
138
|
+
let startPtr = ctx.p++;
|
|
159
139
|
let res = [];
|
|
160
140
|
let c;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (c ===
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
ptr: ptr - 1,
|
|
167
|
-
});
|
|
141
|
+
while (ctx.p < ctx.s.length) {
|
|
142
|
+
skipVoid(ctx);
|
|
143
|
+
if ((c = ctx.s.charCodeAt(ctx.p)) === 0x5d /* ] */) {
|
|
144
|
+
ctx.p++;
|
|
145
|
+
return res;
|
|
168
146
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
res.push(e[0]);
|
|
174
|
-
ptr = e[1];
|
|
147
|
+
res.push(extractValue(ctx, 0x5d /* ] */));
|
|
148
|
+
skipVoid(ctx);
|
|
149
|
+
if ((c = ctx.s.charCodeAt(ctx.p++)) === 0x5d /* ] */) {
|
|
150
|
+
return res;
|
|
175
151
|
}
|
|
152
|
+
if (c !== 0x2c /* , */)
|
|
153
|
+
TomlError.x('expected comma or end of structure', ctx, ctx.p - 1);
|
|
176
154
|
}
|
|
177
|
-
|
|
178
|
-
throw new TomlError('unfinished array encountered', {
|
|
179
|
-
toml: str,
|
|
180
|
-
ptr: ptr,
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
return [res, ptr];
|
|
155
|
+
TomlError.x('unfinished array', ctx, startPtr);
|
|
184
156
|
}
|
|
@@ -26,88 +26,32 @@
|
|
|
26
26
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
28
|
import { TomlError } from './error.js';
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (str[idx - 1] === '\r')
|
|
38
|
-
idx--;
|
|
39
|
-
return idx <= end ? idx : -1;
|
|
40
|
-
}
|
|
41
|
-
export function skipComment(str, ptr) {
|
|
42
|
-
for (let i = ptr; i < str.length; i++) {
|
|
43
|
-
let c = str[i];
|
|
44
|
-
if (c === '\n')
|
|
45
|
-
return i;
|
|
46
|
-
if (c === '\r' && str[i + 1] === '\n')
|
|
47
|
-
return i + 1;
|
|
48
|
-
if ((c < '\x20' && c !== '\t') || c === '\x7f') {
|
|
49
|
-
throw new TomlError('control characters are not allowed in comments', {
|
|
50
|
-
toml: str,
|
|
51
|
-
ptr: ptr,
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return str.length;
|
|
56
|
-
}
|
|
57
|
-
export function skipVoid(str, ptr, banNewLines, banComments) {
|
|
58
|
-
let c;
|
|
59
|
-
while (1) {
|
|
60
|
-
while ((c = str[ptr]) === ' ' || c === '\t' || (!banNewLines && (c === '\n' || c === '\r' && str[ptr + 1] === '\n')))
|
|
61
|
-
ptr++;
|
|
62
|
-
// Tucking the return statement here would save 5 characters >:)
|
|
63
|
-
// But TypeScript fails to detect there is no way to exit the loop so it complains about the lack of final return
|
|
64
|
-
if (banComments || c !== '#')
|
|
29
|
+
/** @internal */
|
|
30
|
+
export function skipComment(ctx) {
|
|
31
|
+
for (; ctx.p < ctx.s.length; ctx.p++) {
|
|
32
|
+
let c = ctx.s.charCodeAt(ctx.p);
|
|
33
|
+
if (c === 0xa /* \n */)
|
|
34
|
+
break;
|
|
35
|
+
if (c === 0xd /* \r */ && ctx.s.charCodeAt(ctx.p + 1) === 0xa /* \n */) {
|
|
36
|
+
ctx.p++;
|
|
65
37
|
break;
|
|
66
|
-
ptr = skipComment(str, ptr);
|
|
67
|
-
}
|
|
68
|
-
return ptr;
|
|
69
|
-
}
|
|
70
|
-
export function skipUntil(str, ptr, sep, end, banNewLines = false) {
|
|
71
|
-
if (!end) {
|
|
72
|
-
ptr = indexOfNewline(str, ptr);
|
|
73
|
-
return ptr < 0 ? str.length : ptr;
|
|
74
|
-
}
|
|
75
|
-
for (let i = ptr; i < str.length; i++) {
|
|
76
|
-
let c = str[i];
|
|
77
|
-
if (c === '#') {
|
|
78
|
-
i = indexOfNewline(str, i);
|
|
79
|
-
if (i < 0)
|
|
80
|
-
break;
|
|
81
|
-
}
|
|
82
|
-
else if (c === sep) {
|
|
83
|
-
return i + 1;
|
|
84
38
|
}
|
|
85
|
-
|
|
86
|
-
|
|
39
|
+
if ((c < 0x20 && c !== 0x9 /* \t */) || c === 0x7f) {
|
|
40
|
+
TomlError.x('control characters are not allowed in comments', ctx);
|
|
87
41
|
}
|
|
88
42
|
}
|
|
89
|
-
throw new TomlError('cannot find end of structure', {
|
|
90
|
-
toml: str,
|
|
91
|
-
ptr: ptr
|
|
92
|
-
});
|
|
93
43
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
let
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (str[seek] === first)
|
|
107
|
-
seek++;
|
|
108
|
-
if (str[seek] === first)
|
|
109
|
-
seek++;
|
|
110
|
-
}
|
|
44
|
+
/** @internal */
|
|
45
|
+
export function skipVoid(ctx, banNewLines, banComments) {
|
|
46
|
+
let c;
|
|
47
|
+
while (ctx.p < ctx.s.length) {
|
|
48
|
+
while (ctx.p < ctx.s.length && ((c = ctx.s.charCodeAt(ctx.p)) === 0x20 ||
|
|
49
|
+
c === 0x9 /* \t */ ||
|
|
50
|
+
(!banNewLines &&
|
|
51
|
+
(c === 0xa /* \n */ || (c === 0xd /* \r */ && ctx.s.charCodeAt(ctx.p + 1) === 0xa /* \n */)))))
|
|
52
|
+
ctx.p++;
|
|
53
|
+
if (banComments || c !== 0x23 /* # */)
|
|
54
|
+
break;
|
|
55
|
+
skipComment(ctx);
|
|
111
56
|
}
|
|
112
|
-
return seek;
|
|
113
57
|
}
|
package/dist/version.js
CHANGED
package/docs/models.md
CHANGED
|
@@ -80,3 +80,13 @@ validator. Every task still uses the existing exact-version, hook, workspace,
|
|
|
80
80
|
and no-plan checks. Source review is against kimi-code 2.0.0 (`1b89e4b0`),
|
|
81
81
|
including `kosongConfig/configSection.ts`, `envOverlay.ts`, and
|
|
82
82
|
`cli/v2/run-v2-print.ts`.
|
|
83
|
+
|
|
84
|
+
## Requested thinking effort
|
|
85
|
+
|
|
86
|
+
`--thinking <effort>` requests per-run effort through `KIMI_MODEL_THINKING_EFFORT`, never a CLI flag or saved-default change; omitted flags preserve the operator-owned ambient variable, and resume does not inherit a previous job's request. Providers that are not trait-driven silently ignore it, as does a base level already `off`; an `alwaysThinking` model receives `off` unnormalized. Stream-json carries no thinking deltas (`writeThinkingDelta() {}`), so the plugin cannot verify whether the request was honoured.
|
|
87
|
+
|
|
88
|
+
Use `--thinking off`, `--thinking high`, or `--thinking=<effort>` before the prompt. Values are lowercased and must match `/^[a-z][a-z0-9-]{0,31}$/` (a plugin-owned syntax bound; a future upstream token outside it is rejected before upstream sees it); upstream per-model `supportEfforts`, not a plugin enum, determines supported values. `--no-thinking` is an error: use `--thinking off`. In CLI 2.2.0 only the three Moonshot `kimi*` provider definitions are trait-driven. BYO providers ignore the request silently; an always-thinking model may remain thinking.
|
|
89
|
+
|
|
90
|
+
Jobs persist nullable `thinking_effort`; status and `result --json` expose `thinking_effort_requested`, not observed effort. Detached ask/rescue workers replay the request. A resume without `--thinking` exports no new override (any ambient operator value remains). No config.toml write occurs.
|
|
91
|
+
|
|
92
|
+
The review gate requests `off` by default. `KIMI_PLUGIN_CC_REVIEW_GATE_THINKING=inherit` exports no override; another non-empty value is lowercased and must match the same regex. Unset or empty means `off`; an invalid value makes the gate skip visibly. The gate remains fail-open on its 8 s timeout: a BYO provider or always-thinking model can ignore the request, and even an honoured request does not guarantee completion within the budget.
|
|
@@ -6,7 +6,11 @@ remain available. The package has no install scripts and no separate CLI.
|
|
|
6
6
|
|
|
7
7
|
## Publishing status
|
|
8
8
|
|
|
9
|
-
As of
|
|
9
|
+
As of October 15, 2026, [2.2.0 is live on npm](https://www.npmjs.com/package/kimi-plugin-cc/v/2.2.0), published by
|
|
10
|
+
the release-event run of `publish.yml` (run 38658918855) through GitHub Actions OIDC with a signed
|
|
11
|
+
provenance statement (sigstore log index 3256863983) — the first release where the tag-triggered
|
|
12
|
+
path worked end to end without a manual dispatch. 2.0.8 (same day, run 38650044033) was the first
|
|
13
|
+
OIDC publication; 2.0.7 (September 26) was the hand-published bootstrap.
|
|
10
14
|
The first upload used the validated GitHub Actions artifact and interactive npm
|
|
11
15
|
authentication. Its public tarball matched that artifact byte-for-byte, and a
|
|
12
16
|
fresh registry install passed isolated setup/check for both hosts.
|
|
@@ -17,6 +21,25 @@ The trusted publisher is configured for `linxule/kimi-plugin-cc`, workflow
|
|
|
17
21
|
use short-lived OIDC credentials, without a stored npm token or interactive 2FA.
|
|
18
22
|
The first npm OIDC publication will be the next release; do not republish 2.0.7.
|
|
19
23
|
|
|
24
|
+
**2026-10-15 status.** The `v2.0.8` release triggered the first OIDC attempt. It
|
|
25
|
+
failed twice on the publish step for reasons unrelated to the package: current
|
|
26
|
+
npm parses a bare `package/<file>.tgz` argument as the GitHub shorthand
|
|
27
|
+
`github:package/<file>` (fixed in `publish.yml`, which now locates the tarball
|
|
28
|
+
and publishes an anchored `./` path), and the manual re-dispatch then received
|
|
29
|
+
`404 Not Found - PUT https://registry.npmjs.org/kimi-plugin-cc`, the response
|
|
30
|
+
npm gives when the OIDC token exchange is refused. The GitHub Actions side
|
|
31
|
+
checks out (environment `npm` exists with no protection rules;
|
|
32
|
+
`NPM_TRUSTED_PUBLISHING=true`), so the cause was on npmjs.com: the trusted-publisher binding created on
|
|
33
|
+
September 26 had **expired unused** (npm expires a binding that never publishes).
|
|
34
|
+
Deleting it and creating a new one (GitHub Actions, `linxule` / `kimi-plugin-cc` /
|
|
35
|
+
`publish.yml` / environment `npm`, with *Allow npm publish* ticked) and
|
|
36
|
+
dispatching `publish.yml` with `tag=v2.0.8` published 2.0.8 with provenance. A new
|
|
37
|
+
binding shows *Pending validation* until its first publish, which must happen
|
|
38
|
+
within about a day; publish promptly after creating one, and expect to recreate it
|
|
39
|
+
after a long gap between releases. Note that a `release` event runs the workflow
|
|
40
|
+
file at the tag, so fixes to `publish.yml` reach an existing tag only through
|
|
41
|
+
`workflow_dispatch`.
|
|
42
|
+
|
|
20
43
|
## Validation
|
|
21
44
|
|
|
22
45
|
Use the repository's normal version bump and generated-surface procedure in
|
package/docs/safety.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Safety
|
|
2
2
|
|
|
3
|
-
This guide describes the shipped 2.0
|
|
3
|
+
This guide describes the shipped 2.2.0 runtime. Read-only tasks deny file writes and shell commands. Rescue and pursue can edit your workspace. Write-swarm returns a patch from a temporary Git worktree.
|
|
4
4
|
|
|
5
5
|
Native agent-core-v2 is certified at exact CLI versions `0.42.0`, `0.43.0`, `0.43.1`, `2.0.0`, `2.0.1`, `2.0.2`, `2.1.0`, and `2.1.1`, with plan mode disabled. The [runtime certification table](../runtime/kimi-engine.ts) controls routing. The hook is not an operating-system sandbox.
|
|
6
6
|
|
|
@@ -74,7 +74,7 @@ Key constraints (verified by [`runtime/hooks/managed-block.ts`](../runtime/hooks
|
|
|
74
74
|
3. **TOML basic-string escaping.** The command field is a TOML basic string. Quotes, backslashes, newlines, and control characters in the resolved hook path are escaped during install; paths containing characters that cannot be safely escaped (literal `"`, raw control chars) are rejected up front with `SETUP_HOOK_PATH_UNSAFE`.
|
|
75
75
|
4. **Exact marker grammar.** The verifier rejects stray comments containing the marker tag, partial references, duplicate blocks (from a setup race), and orphan markers (from a manual edit). The same parser is used by both the installer and the per-call verifier so the two cannot disagree.
|
|
76
76
|
5. **Exact command equality, per host.** The verifier reconstructs the canonical command byte string from the current env and equality-checks the installed `command` (never a substring — a crafted `true # /path/to/approval-hook.js` runs only `true` and would auto-allow). This holds *per host id* (below): each host verifies its own block.
|
|
77
|
-
6. **Full-config parse and whole-hook-array validation.** The verifier parses the complete file with vendored `smol-toml@1.
|
|
77
|
+
6. **Full-config parse and whole-hook-array validation.** The verifier parses the complete file with vendored `smol-toml@1.9.1` with upstream fixes included and no local JavaScript modifications (see `runtime/vendor/smol-toml/README.md`), before inspecting the managed block. It then applies upstream's strict config schema to every configured hook (`event`, optional string `matcher`, non-empty `command`, optional integer `timeout` 1–600, no extra fields). A malformed unrelated TOML value or one invalid foreign hook can make kimi-code discard enforcement; both therefore fail verification.
|
|
78
78
|
7. **Serialized, identity-bound setup mutations.** Install and uninstall hold a private `0o600` sibling lock across the complete read-modify-write transaction. The candidate lock is published atomically; lock reads are no-follow, nonblocking, regular-file-only, and capped at 4 KiB. Acquisition is bounded, live owners are never stolen, stale recovery is guarded by a nonrecursive recovery lease, and inode/token ownership is rechecked before config mutation or lock removal. Simultaneous Claude Code/Codex setup runs therefore cannot lose either host's block, and a replaced lock is never treated as ours. A newly created Kimi home is `0o700`; atomic config writes remain `0o600`.
|
|
79
79
|
8. **Inline hook arrays are normalized before insertion.** kimi-code accepts both `hooks = [...]` and `[[hooks]]`, but appending a managed array-of-tables block after an inline assignment can produce a conflicting document. Setup converts a valid inline hook array to canonical `[[hooks]]` tables before inserting the host block and emits an explicit warning that formatting and comments inside that assignment are normalized. Surrounding config bytes are preserved.
|
|
80
80
|
|
|
@@ -225,6 +225,53 @@ If another installed host still points to an older hook, that hook may veto thes
|
|
|
225
225
|
- **Field-proven by a real-binary smoke.** `tests/runtime/real-binary-smoke.test.ts` runs the real `runSwarm --write` and asserts the POSITIVE end-to-end (a `coder` subagent's edits land in the worktree, captured as a patch; the user's real tree is byte-identical + git-clean; the worktree is cleaned up) plus the NEGATIVE (an absolute-path write outside the trusted root is hook-denied). It is the check that catches `tool_input` field-name drift — `Write`/`Edit` carry `path`, not `file_path`, and reading the wrong key denies every real write silently.
|
|
226
226
|
- **Model-invocable agent (v1.5), patch-only by construction.** Following the field-proof above, `--write` now has a `kimi-swarm-write` subagent so the main Claude thread can dispatch a write fan-out on its own judgement — the same human-command + model-invocable-agent split the rest of the suite uses. Auto-dispatch is a safe extension here because it widens **no** write surface and removes **no** bound: the agent path runs the identical `runSwarm --write` code, so edits still land only in the throwaway worktree, the managed hook still gates every `coder` subagent, the patch is still handed back for the user to apply (**the plugin never applies or commits**), and `--budget` + default `--max-concurrency` 1 + the hook requirement all still hold. In fact write-swarm is a *less* dangerous agent than the `kimi-pursue` agent already shipped: pursue writes directly into the workspace, whereas write-swarm's output is a patch the human reviews before anything reaches a real tree. Because it is still a write surface, the agent description demands BOTH signals — many disjoint write targets AND explicit fan-out intent — and steers single edits to `kimi-rescue`, read-only fan-outs to `kimi-swarm`, and autonomous loops to `kimi-pursue`. Default `--max-concurrency` stays **1**; raising it (concurrent writers) remains a deliberate, human-or-explicitly-requested choice.
|
|
227
227
|
|
|
228
|
+
## Response budgets and partial output (2.2.0)
|
|
229
|
+
|
|
230
|
+
Every single-turn command runs under a wall-clock budget: ask, review and
|
|
231
|
+
challenge default to 30 minutes, rescue to 45, and `--budget <dur>` (at most
|
|
232
|
+
24h) overrides it per job. The budget is persisted on the job row, so a detached
|
|
233
|
+
worker and a same-operation resume use the same ceiling. For these commands the
|
|
234
|
+
budget is a response-time limit, not a safety bound: a timeout is a safe
|
|
235
|
+
failure. The job stays `failed`; whatever assistant prose had settled is written
|
|
236
|
+
into the artifact under a heading that says it is NOT a final answer, and
|
|
237
|
+
`result <jobId> --json` reports `partial_output: true` when prose exists.
|
|
238
|
+
Cancellation and nonzero exits do not capture partial output. A session ID is kept if Kimi announced it or, on a native-v2 budget timeout, recovered from the session store when exactly one session matches this spawn — created between spawn and settlement in the same directory AND whose journal opens with this job's exact prompt; `result --json` identifies the source in `kimi_session_id_source`, and `error.details.session_recovery` says why no ID was recovered (`none`, `journal_missing:<n>`, `digest_mismatch:<n>`, `ambiguous:<n>`, `enumeration_capped`, `engine_unobserved`). Recovery is bounded and refuses ambiguity, incomplete enumeration, and IDs already used by another job on this host. The prompt binding is what makes attribution proof rather than probability: a concurrent interactive session in the same directory, another host's finished job (host stores cannot see each other's IDs) or a `state.json` planted by repository code running under rescue all fail it unless they carry the exact prompt, and a planted clean journal could otherwise replay attacker-written turns into the next resume. Recovery is skipped when the run never emitted the `system.version` marker, since resume would refuse the row as lineage-unknown anyway. Recovered sessions still require proven native-v2 lineage and the raw plan-taint scan before resume. Inherited budgets are printed to stderr at launch; status and `result --json` expose `budget_source` (`explicit`, `inherited`, or `default`; old non-null budgets report `unknown`).
|
|
239
|
+
|
|
240
|
+
Pursue and swarm keep their ceilings as the sole hard bound on autonomy and
|
|
241
|
+
cost. One nuance: a run whose process exits cleanly in the same event-loop tick
|
|
242
|
+
as the budget timer is accepted as a success rather than discarded, so a goal
|
|
243
|
+
can complete at most one tick past its ceiling — teardown has already settled by
|
|
244
|
+
then, and nothing runs longer.
|
|
245
|
+
|
|
246
|
+
Every spawn also deletes `KIMI_CODE_TRUST_WORKSPACE` from the child
|
|
247
|
+
environment (kimi-code 2.2.0): a trusted workspace boots repo-defined project
|
|
248
|
+
MCP servers at bootstrap, outside the PreToolUse hook, and an inherited value
|
|
249
|
+
would have trusted every plugin spawn including swarm-write's throwaway
|
|
250
|
+
worktree. A directory the operator trusted interactively in the Kimi TUI still
|
|
251
|
+
has that property; that persisted-trust route is a documented residual, not
|
|
252
|
+
something the plugin can close.
|
|
253
|
+
|
|
254
|
+
## Running a newer Kimi than the plugin certifies
|
|
255
|
+
|
|
256
|
+
The plugin refuses any kimi-code version it has not certified, so an operator
|
|
257
|
+
who tracks `@latest` loses every `/kimi:*` command until the next certification.
|
|
258
|
+
The clean way to have both is to give the plugin its own binary: install the
|
|
259
|
+
highest certified version somewhere stable and point `KIMI_PLUGIN_CC_KIMI_BIN`
|
|
260
|
+
at it (the runtime resolves that path instead of `kimi` on `PATH`; every spawn
|
|
261
|
+
still exports `KIMI_CODE_NO_AUTO_UPDATE=1`, so the pinned copy never drifts).
|
|
262
|
+
|
|
263
|
+
```sh
|
|
264
|
+
PIN=~/.local/share/kimi-plugin-cc/kimi-bin/2.2.0
|
|
265
|
+
mkdir -p "$PIN" && cd "$PIN" && printf '{"name":"kimi-plugin-cc-pin","private":true}\n' > package.json
|
|
266
|
+
bun add @moonshot-ai/kimi-code@2.2.0
|
|
267
|
+
export KIMI_PLUGIN_CC_KIMI_BIN="$PIN/node_modules/.bin/kimi" # e.g. in ~/.zshenv
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Both binaries share `~/.kimi-code` (login, config, hook), so nothing else
|
|
271
|
+
changes. The certified maximum can be read from the installed plugin
|
|
272
|
+
(`NATIVE_V2_CERTIFIED_VERSIONS` in `dist/kimi-engine.js`), which lets an upgrade
|
|
273
|
+
script bump the pin automatically after each certification.
|
|
274
|
+
|
|
228
275
|
## The setup probe
|
|
229
276
|
|
|
230
277
|
`/kimi:setup` runs a two-layer probe before reporting success:
|
|
@@ -316,3 +363,13 @@ Agents use `retryable_after_setup`, not `drift_axis` alone. They run setup for t
|
|
|
316
363
|
## Reporting safety issues
|
|
317
364
|
|
|
318
365
|
If you find a way to coax /kimi:review, /kimi:challenge, /kimi:review_gate, or /kimi:ask into running a non-read tool — or to make /kimi:rescue mutate `.git/` or escape the workspace — please open a GitHub security advisory rather than a public issue.
|
|
366
|
+
|
|
367
|
+
## Hook-escape monitor: detection evidence
|
|
368
|
+
|
|
369
|
+
**Hook-escape monitor** (§1): the cli-client replays the pure hook policy on every streamed `tool_calls` entry; a call the policy denies whose tool result is not the hook's denial (byte-exact, or with upstream's repeat-breaker `<system-reminder>` decoration / handoff text) is recorded as `mismatch`, and a denied call still without a result at settlement as `unresolved`. Findings are **detection evidence, never a failure**: logged (`hook_escape`), persisted on the job row (`hook_escapes`, JSON), exposed by `status`/`result --json`, printed as a stderr `safety hook notice`, and carried in timeout details; the run continues, the job's outcome is unchanged, and the review gate stays fail-open and only annotates. The stream has no outcome field, so a mismatch is equally an upstream pre-hook rejection (unknown tool, disabled tool, invalid args, sensitive path, per-tool resolve errors), a coexisting hook or permission policy blocking first, or hook drift — failing the job needs positive execution evidence this stream does not provide. Streamed calls under read-only labels are covered (swarm subagents are in-process, not streamed); write labels only for the pure denials (plan/goal tools).
|
|
370
|
+
|
|
371
|
+
A denied attempt alone is not a finding: the hook's denial text in the corresponding tool result (byte-exact, or carrying upstream's repeat-breaker decoration) proves enforcement and clears it. Anything else is recorded as `mismatch` with a 200-character excerpt; a denied call with no result at settlement as `unresolved`. **What a finding means:** the model received something other than the managed denial. On certified 2.2.0 that is produced just as readily by calls upstream rejects before the hook runs (`Tool "LS" not found`, `Invalid args for tool …`, the sensitive-path `PathSecurityError` for `.env`, per-tool resolve errors, `Tool skipped because a previous tool call stopped the turn.`), by a coexisting PreToolUse hook ahead of the managed block or an upstream permission policy blocking first, or by a cancel/budget abort landing before the result — none of which executed anything — as by a hook that failed open. Because the stream carries no outcome field, the plugin cannot tell these apart, so it reports and does not fail: the job completes or fails on its own merits, `status`/`result --json` carry `hook_escapes`, stderr prints a `safety hook notice`, and the review gate annotates `systemMessage` without changing its decision. Treat a finding as a prompt to run `/kimi:setup --check` and read the excerpt, not as proof of a breach; treat a *recurring* `mismatch` whose excerpt looks like tool output (`Wrote N bytes to …`) as a drifted hook. Coverage is streamed calls under read-only labels and pure denials under write labels — not filesystem-dependent rescue allowlist decisions, not swarm subagent calls (in-process, never streamed). Non-vacuous live control (CLI 2.2.0, 2026-10-15): with the hook command pointed at a nonexistent script upstream failed open, `Write` created the file, and the finding was `mismatch` with excerpt `Wrote 7 bytes to ESCAPE.txt`; with the hook intact the same prompt produced the byte-exact denial and no finding. Enforcement (stopping the run, failing the job) is deliberately not shipped: it needs positive execution evidence. The parked upstream ask is an `outcome: executed|vetoed|rejected` field on print-mode tool records; a plugin-side alternative is a per-job trace the hook writes before it exits.
|
|
372
|
+
|
|
373
|
+
## Review-gate thinking request
|
|
374
|
+
|
|
375
|
+
The gate requests `off` through `KIMI_MODEL_THINKING_EFFORT` by default. `KIMI_PLUGIN_CC_REVIEW_GATE_THINKING=inherit` leaves the ambient environment alone; any other non-empty value matching `/^[a-z][a-z0-9-]{0,31}$/` is passed verbatim. This is best-effort, never an enforced latency guarantee: non-trait-driven/BYO providers ignore it silently, an already-off base remains off, and an always-thinking model receives `off` unnormalized and may continue reasoning. Stream-json has no thinking deltas, so honouring the request cannot be observed. The 8 s budget and fail-open-on-timeout contract are unchanged; a hook-escape finding only annotates the gate's `systemMessage`. `KIMI_PLUGIN_CC_REVIEW_GATE_THINKING` is lowercased like `--thinking`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kimi",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "Codex plugin that delegates review, challenge, ask, rescue, pursue, and swarm workflows to the local kimi-code CLI through the kimi-plugin-cc companion runtime.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "linxule"
|