@kawacode/mcp 6.1.5 → 6.6.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.md.example +2 -0
- package/build/index.js +13 -1
- package/build/index.js.map +1 -1
- package/build/kawacode-on-pre-edit.d.ts +5 -0
- package/build/kawacode-on-pre-edit.js +45 -6
- package/build/kawacode-on-pre-edit.js.map +1 -1
- package/build/kawacode-on-stop.d.ts +49 -23
- package/build/kawacode-on-stop.js +233 -38
- package/build/kawacode-on-stop.js.map +1 -1
- package/build/services/muninn-ipc.d.ts +19 -1
- package/build/services/muninn-ipc.js +20 -2
- package/build/services/muninn-ipc.js.map +1 -1
- package/build/stop/uncompleted-commit.d.ts +45 -0
- package/build/stop/uncompleted-commit.js +117 -0
- package/build/stop/uncompleted-commit.js.map +1 -0
- package/build/stop/uncompleted-commit.test.d.ts +1 -0
- package/build/stop/uncompleted-commit.test.js +105 -0
- package/build/stop/uncompleted-commit.test.js.map +1 -0
- package/build/tools/activate-intent.d.ts +1 -14
- package/build/tools/activate-intent.js +17 -56
- package/build/tools/activate-intent.js.map +1 -1
- package/build/tools/arbiter-apply.d.ts +132 -0
- package/build/tools/arbiter-apply.js +59 -0
- package/build/tools/arbiter-apply.js.map +1 -0
- package/build/tools/arbiter-resolve.d.ts +132 -0
- package/build/tools/arbiter-resolve.js +58 -0
- package/build/tools/arbiter-resolve.js.map +1 -0
- package/build/tools/check-active-intent.d.ts +21 -12
- package/build/tools/check-active-intent.js +26 -13
- package/build/tools/check-active-intent.js.map +1 -1
- package/build/tools/complete-intent.d.ts +29 -0
- package/build/tools/complete-intent.js +26 -28
- package/build/tools/complete-intent.js.map +1 -1
- package/build/tools/create-intent.d.ts +1 -21
- package/build/tools/create-intent.js +18 -106
- package/build/tools/create-intent.js.map +1 -1
- package/build/tools/get-decision-detail.d.ts +109 -0
- package/build/tools/get-decision-detail.js +57 -0
- package/build/tools/get-decision-detail.js.map +1 -0
- package/build/tools/get-project-decisions.d.ts +0 -4
- package/build/tools/get-project-decisions.js +4 -6
- package/build/tools/get-project-decisions.js.map +1 -1
- package/build/tools/get-relevant-context.d.ts +0 -1
- package/build/tools/get-relevant-context.js +4 -2
- package/build/tools/get-relevant-context.js.map +1 -1
- package/build/tools/get-resolution-context.d.ts +154 -0
- package/build/tools/get-resolution-context.js +78 -0
- package/build/tools/get-resolution-context.js.map +1 -0
- package/build/tools/get-session-decisions.d.ts +0 -5
- package/build/tools/get-session-decisions.js +5 -5
- package/build/tools/get-session-decisions.js.map +1 -1
- package/build/tools/index.d.ts +210 -7
- package/build/tools/index.js +13 -3
- package/build/tools/index.js.map +1 -1
- package/build/tools/list-team-intents.d.ts +6 -6
- package/build/tools/list-team-intents.js +2 -2
- package/build/tools/list-team-intents.js.map +1 -1
- package/build/tools/pre-edit-decision-check.js +2 -0
- package/build/tools/pre-edit-decision-check.js.map +1 -1
- package/build/tools/record-decision.d.ts +76 -0
- package/build/tools/record-decision.js +10 -0
- package/build/tools/record-decision.js.map +1 -1
- package/package.json +2 -2
|
@@ -9,7 +9,25 @@
|
|
|
9
9
|
* - Request/response correlation via _msgId
|
|
10
10
|
* - 30s default timeout per request, overridable per call
|
|
11
11
|
*/
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Stable session ID for this MCP process — identifies this agent/session for
|
|
14
|
+
* intent attribution AND for the per-session "current" intent pointer in Muninn
|
|
15
|
+
* (IMPLEMENTATION_PLAN_MULTI_ACTIVE_INTENTS.md §2 D1).
|
|
16
|
+
*
|
|
17
|
+
* Prefer Claude Code's `CLAUDE_CODE_SESSION_ID`: it's the SAME id the thought-
|
|
18
|
+
* capture path keys on (the `thoughts/active/session-{id}.jsonl` filename and the
|
|
19
|
+
* extractor trigger), so the IPC and capture worlds converge on one value, and it
|
|
20
|
+
* is stable across MCP reconnects (a fresh socket `caw` recovers the same focus).
|
|
21
|
+
* Subagents share their parent session's id — there is no per-subagent id at the
|
|
22
|
+
* MCP layer (see plan §11).
|
|
23
|
+
*
|
|
24
|
+
* Fallback: hosts that don't set the env var (Cursor/Windsurf, older Claude Code)
|
|
25
|
+
* get a generated `mcp-<random>`. Those have no Claude thought-capture, so capture
|
|
26
|
+
* routing is moot and the random id serves only as an IPC discriminator.
|
|
27
|
+
*
|
|
28
|
+
* Stamped as `_agentId` on every outgoing message (see `request()` below); Muninn
|
|
29
|
+
* lifts it into `IpcMessage.aid` and keys the per-session current pointer on it.
|
|
30
|
+
*/
|
|
13
31
|
export declare const SESSION_ID: string;
|
|
14
32
|
/**
|
|
15
33
|
* Connect to Muninn's Huginn IPC socket.
|
|
@@ -16,8 +16,26 @@ import * as os from 'os';
|
|
|
16
16
|
import * as crypto from 'crypto';
|
|
17
17
|
const EXTENSION_ID = 'mcp';
|
|
18
18
|
const EXTENSION_DOMAINS = ['intent', 'intent-block', 'decision', 'claude-code', 'code', 'inference'];
|
|
19
|
-
/**
|
|
20
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Stable session ID for this MCP process — identifies this agent/session for
|
|
21
|
+
* intent attribution AND for the per-session "current" intent pointer in Muninn
|
|
22
|
+
* (IMPLEMENTATION_PLAN_MULTI_ACTIVE_INTENTS.md §2 D1).
|
|
23
|
+
*
|
|
24
|
+
* Prefer Claude Code's `CLAUDE_CODE_SESSION_ID`: it's the SAME id the thought-
|
|
25
|
+
* capture path keys on (the `thoughts/active/session-{id}.jsonl` filename and the
|
|
26
|
+
* extractor trigger), so the IPC and capture worlds converge on one value, and it
|
|
27
|
+
* is stable across MCP reconnects (a fresh socket `caw` recovers the same focus).
|
|
28
|
+
* Subagents share their parent session's id — there is no per-subagent id at the
|
|
29
|
+
* MCP layer (see plan §11).
|
|
30
|
+
*
|
|
31
|
+
* Fallback: hosts that don't set the env var (Cursor/Windsurf, older Claude Code)
|
|
32
|
+
* get a generated `mcp-<random>`. Those have no Claude thought-capture, so capture
|
|
33
|
+
* routing is moot and the random id serves only as an IPC discriminator.
|
|
34
|
+
*
|
|
35
|
+
* Stamped as `_agentId` on every outgoing message (see `request()` below); Muninn
|
|
36
|
+
* lifts it into `IpcMessage.aid` and keys the per-session current pointer on it.
|
|
37
|
+
*/
|
|
38
|
+
export const SESSION_ID = process.env.CLAUDE_CODE_SESSION_ID || `mcp-${crypto.randomBytes(4).toString('hex')}`;
|
|
21
39
|
const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
|
|
22
40
|
const HANDSHAKE_TIMEOUT_MS = 10_000;
|
|
23
41
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"muninn-ipc.js","sourceRoot":"","sources":["../../src/services/muninn-ipc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,GAAG,MAAM,KAAK,CAAA;AAC1B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AACxB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAC5B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AACxB,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAA;AAEhC,MAAM,YAAY,GAAG,KAAK,CAAA;AAC1B,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,CAAC,CAAA;AAEpG
|
|
1
|
+
{"version":3,"file":"muninn-ipc.js","sourceRoot":"","sources":["../../src/services/muninn-ipc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure transcript detection for the complete_intent hard gate (kawacode-on-stop
|
|
3
|
+
* job 3). Kept separate from the bin entry so it's unit-testable without
|
|
4
|
+
* triggering the hook's main().
|
|
5
|
+
*
|
|
6
|
+
* The signal we want: the agent ran `git commit` but never finalized the work
|
|
7
|
+
* with complete_intent. We read Claude Code's own transcript (harness
|
|
8
|
+
* introspection — not Muninn's concern) and compare the position of the last
|
|
9
|
+
* SUCCESSFUL commit against the last complete_intent call.
|
|
10
|
+
*/
|
|
11
|
+
/** Flatten a tool_result `content` (string | array of {type,text}) to plain text. */
|
|
12
|
+
export declare function toolResultText(content: unknown): string;
|
|
13
|
+
/** A Bash command that *invokes* `git commit` (incl. `git -C <path> commit`),
|
|
14
|
+
* excluding dry runs. NOTE: a true match here is necessary but NOT sufficient —
|
|
15
|
+
* a command can merely MENTION "git commit" as data (printf/echo/heredoc/docs,
|
|
16
|
+
* `git log --grep`). Confirm an actual commit with {@link looksLikeCommitOutput}
|
|
17
|
+
* on the tool_result before treating it as a commit. */
|
|
18
|
+
export declare function isGitCommitCommand(name: string, cmd: string): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* True when text contains git's commit-success line: `[<ref> <shorthash>] …`
|
|
21
|
+
* (covers commit / amend / merge / cherry-pick / root-commit). This is the
|
|
22
|
+
* authoritative "a commit actually happened" signal — `git log`/`git show` and
|
|
23
|
+
* non-git output don't produce a bracketed short-hash line, and a command that
|
|
24
|
+
* only mentions "git commit" as data produces no such output at all.
|
|
25
|
+
*
|
|
26
|
+
* Tradeoff: `git commit --quiet` suppresses this line, so a quiet commit is a
|
|
27
|
+
* false NEGATIVE (no gate). That's the safe bias for a hard gate — a missed nag
|
|
28
|
+
* is far less disruptive than a false block (the printf-in-transcript bug).
|
|
29
|
+
*/
|
|
30
|
+
export declare function looksLikeCommitOutput(text: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* True when the transcript shows a SUCCESSFUL `git commit` tool_use that lands
|
|
33
|
+
* after the most recent complete_intent tool_use (or with no complete_intent
|
|
34
|
+
* after it) — i.e. the agent committed without finalizing.
|
|
35
|
+
*
|
|
36
|
+
* A commit counts only when BOTH hold: the command invokes git commit AND its
|
|
37
|
+
* tool_result carries the commit-success signature (not is_error). Requiring
|
|
38
|
+
* the result signature is what stops a command that merely *mentions* "git
|
|
39
|
+
* commit" (e.g. a printf crafting a fixture) from being read as a real commit.
|
|
40
|
+
* A complete_intent call counts even if it later failed (conflicts): the agent
|
|
41
|
+
* tried, so we don't nag.
|
|
42
|
+
*
|
|
43
|
+
* @param transcriptText raw JSONL contents of the Claude Code transcript
|
|
44
|
+
*/
|
|
45
|
+
export declare function detectUncompletedCommit(transcriptText: string): boolean;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure transcript detection for the complete_intent hard gate (kawacode-on-stop
|
|
3
|
+
* job 3). Kept separate from the bin entry so it's unit-testable without
|
|
4
|
+
* triggering the hook's main().
|
|
5
|
+
*
|
|
6
|
+
* The signal we want: the agent ran `git commit` but never finalized the work
|
|
7
|
+
* with complete_intent. We read Claude Code's own transcript (harness
|
|
8
|
+
* introspection — not Muninn's concern) and compare the position of the last
|
|
9
|
+
* SUCCESSFUL commit against the last complete_intent call.
|
|
10
|
+
*/
|
|
11
|
+
/** Flatten a tool_result `content` (string | array of {type,text}) to plain text. */
|
|
12
|
+
export function toolResultText(content) {
|
|
13
|
+
if (typeof content === 'string')
|
|
14
|
+
return content;
|
|
15
|
+
if (Array.isArray(content)) {
|
|
16
|
+
return content
|
|
17
|
+
.map(c => (typeof c === 'string' ? c : typeof c?.text === 'string' ? c.text : ''))
|
|
18
|
+
.join(' ');
|
|
19
|
+
}
|
|
20
|
+
return '';
|
|
21
|
+
}
|
|
22
|
+
/** A Bash command that *invokes* `git commit` (incl. `git -C <path> commit`),
|
|
23
|
+
* excluding dry runs. NOTE: a true match here is necessary but NOT sufficient —
|
|
24
|
+
* a command can merely MENTION "git commit" as data (printf/echo/heredoc/docs,
|
|
25
|
+
* `git log --grep`). Confirm an actual commit with {@link looksLikeCommitOutput}
|
|
26
|
+
* on the tool_result before treating it as a commit. */
|
|
27
|
+
export function isGitCommitCommand(name, cmd) {
|
|
28
|
+
if (name !== 'Bash' || !cmd)
|
|
29
|
+
return false;
|
|
30
|
+
if (/--dry-run/.test(cmd))
|
|
31
|
+
return false;
|
|
32
|
+
return /\bgit\s+(?:-C\s+\S+\s+)?commit\b/.test(cmd);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* True when text contains git's commit-success line: `[<ref> <shorthash>] …`
|
|
36
|
+
* (covers commit / amend / merge / cherry-pick / root-commit). This is the
|
|
37
|
+
* authoritative "a commit actually happened" signal — `git log`/`git show` and
|
|
38
|
+
* non-git output don't produce a bracketed short-hash line, and a command that
|
|
39
|
+
* only mentions "git commit" as data produces no such output at all.
|
|
40
|
+
*
|
|
41
|
+
* Tradeoff: `git commit --quiet` suppresses this line, so a quiet commit is a
|
|
42
|
+
* false NEGATIVE (no gate). That's the safe bias for a hard gate — a missed nag
|
|
43
|
+
* is far less disruptive than a false block (the printf-in-transcript bug).
|
|
44
|
+
*/
|
|
45
|
+
export function looksLikeCommitOutput(text) {
|
|
46
|
+
return /\[[^\]\n]*\b[0-9a-f]{7,40}\b[^\]\n]*\]/.test(text);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* True when the transcript shows a SUCCESSFUL `git commit` tool_use that lands
|
|
50
|
+
* after the most recent complete_intent tool_use (or with no complete_intent
|
|
51
|
+
* after it) — i.e. the agent committed without finalizing.
|
|
52
|
+
*
|
|
53
|
+
* A commit counts only when BOTH hold: the command invokes git commit AND its
|
|
54
|
+
* tool_result carries the commit-success signature (not is_error). Requiring
|
|
55
|
+
* the result signature is what stops a command that merely *mentions* "git
|
|
56
|
+
* commit" (e.g. a printf crafting a fixture) from being read as a real commit.
|
|
57
|
+
* A complete_intent call counts even if it later failed (conflicts): the agent
|
|
58
|
+
* tried, so we don't nag.
|
|
59
|
+
*
|
|
60
|
+
* @param transcriptText raw JSONL contents of the Claude Code transcript
|
|
61
|
+
*/
|
|
62
|
+
export function detectUncompletedCommit(transcriptText) {
|
|
63
|
+
const lines = transcriptText.split('\n');
|
|
64
|
+
const commits = [];
|
|
65
|
+
const results = new Map();
|
|
66
|
+
let lastCompleteIdx = -1;
|
|
67
|
+
for (let i = 0; i < lines.length; i++) {
|
|
68
|
+
const ln = lines[i].trim();
|
|
69
|
+
if (!ln)
|
|
70
|
+
continue;
|
|
71
|
+
let obj;
|
|
72
|
+
try {
|
|
73
|
+
obj = JSON.parse(ln);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const content = obj?.message?.content;
|
|
79
|
+
if (!Array.isArray(content))
|
|
80
|
+
continue;
|
|
81
|
+
for (const item of content) {
|
|
82
|
+
if (item?.type === 'tool_use') {
|
|
83
|
+
const name = item.name || '';
|
|
84
|
+
if (/complete_intent/.test(name)) {
|
|
85
|
+
lastCompleteIdx = i;
|
|
86
|
+
}
|
|
87
|
+
else if (isGitCommitCommand(name, item?.input?.command || '')) {
|
|
88
|
+
commits.push({ idx: i, id: item.id });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (item?.type === 'tool_result' && item.tool_use_id) {
|
|
92
|
+
results.set(item.tool_use_id, {
|
|
93
|
+
isError: item.is_error === true,
|
|
94
|
+
text: toolResultText(item.content),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Most recent commit CONFIRMED by its result signature. A candidate with no
|
|
100
|
+
// result, an errored result, or output lacking the signature does not count.
|
|
101
|
+
let lastCommitIdx = -1;
|
|
102
|
+
for (const c of commits) {
|
|
103
|
+
if (!c.id)
|
|
104
|
+
continue;
|
|
105
|
+
const r = results.get(c.id);
|
|
106
|
+
if (!r || r.isError)
|
|
107
|
+
continue;
|
|
108
|
+
if (!looksLikeCommitOutput(r.text))
|
|
109
|
+
continue;
|
|
110
|
+
if (c.idx > lastCommitIdx)
|
|
111
|
+
lastCommitIdx = c.idx;
|
|
112
|
+
}
|
|
113
|
+
if (lastCommitIdx === -1)
|
|
114
|
+
return false;
|
|
115
|
+
return lastCommitIdx > lastCompleteIdx;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=uncompleted-commit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uncompleted-commit.js","sourceRoot":"","sources":["../../src/stop/uncompleted-commit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { detectUncompletedCommit, isGitCommitCommand, looksLikeCommitOutput, toolResultText, } from './uncompleted-commit.js';
|
|
4
|
+
/** A realistic `git commit` success result (the bracketed short-hash line). */
|
|
5
|
+
const COMMIT_OK = '[main 1a2b3c4] Add the thing\n 1 file changed, 2 insertions(+)';
|
|
6
|
+
// ---- transcript line builders (Claude Code JSONL shape) ----
|
|
7
|
+
function bash(command, id) {
|
|
8
|
+
return JSON.stringify({
|
|
9
|
+
type: 'assistant',
|
|
10
|
+
message: { role: 'assistant', content: [{ type: 'tool_use', name: 'Bash', id, input: { command } }] },
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function toolUse(name, id) {
|
|
14
|
+
return JSON.stringify({
|
|
15
|
+
type: 'assistant',
|
|
16
|
+
message: { role: 'assistant', content: [{ type: 'tool_use', name, id, input: {} }] },
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function result(toolUseId, opts = {}) {
|
|
20
|
+
return JSON.stringify({
|
|
21
|
+
type: 'user',
|
|
22
|
+
message: {
|
|
23
|
+
role: 'user',
|
|
24
|
+
content: [{ type: 'tool_result', tool_use_id: toolUseId, is_error: opts.isError ?? false, content: opts.text ?? 'ok' }],
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
const COMPLETE = 'mcp__kawa-intents__complete_intent';
|
|
29
|
+
test('isGitCommitCommand', async (t) => {
|
|
30
|
+
await t.test('plain commit', () => assert.equal(isGitCommitCommand('Bash', 'git commit -m "x"'), true));
|
|
31
|
+
await t.test('git -C path commit', () => assert.equal(isGitCommitCommand('Bash', 'git -C /repo commit -am "x"'), true));
|
|
32
|
+
await t.test('chained with &&', () => assert.equal(isGitCommitCommand('Bash', 'git add -A && git commit -m "x"'), true));
|
|
33
|
+
await t.test('dry-run excluded', () => assert.equal(isGitCommitCommand('Bash', 'git commit --dry-run'), false));
|
|
34
|
+
await t.test('non-Bash tool excluded', () => assert.equal(isGitCommitCommand('Edit', 'git commit -m "x"'), false));
|
|
35
|
+
await t.test('git log mentioning commit not matched', () => assert.equal(isGitCommitCommand('Bash', 'git log --pretty=%H'), false));
|
|
36
|
+
});
|
|
37
|
+
test('toolResultText flattens shapes', async (t) => {
|
|
38
|
+
await t.test('string', () => assert.equal(toolResultText('hello'), 'hello'));
|
|
39
|
+
await t.test('array of text parts', () => assert.equal(toolResultText([{ type: 'text', text: 'a' }, { type: 'text', text: 'b' }]), 'a b'));
|
|
40
|
+
await t.test('other → empty', () => assert.equal(toolResultText({ foo: 1 }), ''));
|
|
41
|
+
});
|
|
42
|
+
test('looksLikeCommitOutput', async (t) => {
|
|
43
|
+
await t.test('standard commit line', () => assert.equal(looksLikeCommitOutput('[main 1a2b3c4] msg'), true));
|
|
44
|
+
await t.test('root commit', () => assert.equal(looksLikeCommitOutput('[main (root-commit) 0e1f2a3] init'), true));
|
|
45
|
+
await t.test('detached HEAD', () => assert.equal(looksLikeCommitOutput('[detached HEAD abc1234] msg'), true));
|
|
46
|
+
await t.test('nothing-to-commit output → false', () => assert.equal(looksLikeCommitOutput('nothing to commit, working tree clean'), false));
|
|
47
|
+
await t.test('empty (printf wrote a file) → false', () => assert.equal(looksLikeCommitOutput(''), false));
|
|
48
|
+
await t.test('git log oneline → false', () => assert.equal(looksLikeCommitOutput('1a2b3c4 some subject\nded5678 another'), false));
|
|
49
|
+
});
|
|
50
|
+
test('detectUncompletedCommit', async (t) => {
|
|
51
|
+
await t.test('no commit at all → false', () => {
|
|
52
|
+
const t1 = [toolUse('Read', 'r1'), result('r1')].join('\n');
|
|
53
|
+
assert.equal(detectUncompletedCommit(t1), false);
|
|
54
|
+
});
|
|
55
|
+
await t.test('confirmed commit with no completion → true', () => {
|
|
56
|
+
const t1 = [bash('git commit -m "x"', 'c1'), result('c1', { text: COMMIT_OK })].join('\n');
|
|
57
|
+
assert.equal(detectUncompletedCommit(t1), true);
|
|
58
|
+
});
|
|
59
|
+
await t.test('REGRESSION: command merely MENTIONS "git commit" (printf, no commit output) → false', () => {
|
|
60
|
+
// The printf-in-transcript false positive: a Bash command that contains the
|
|
61
|
+
// string "git commit" as data, writing a fixture; its result has no commit
|
|
62
|
+
// signature, so it must NOT be read as a real commit.
|
|
63
|
+
const printf = bash(`printf '%s' '{"command":"git commit -m \\"x\\""}' > /tmp/fixture.jsonl`, 'p1');
|
|
64
|
+
const t1 = [printf, result('p1', { text: '' })].join('\n');
|
|
65
|
+
assert.equal(detectUncompletedCommit(t1), false);
|
|
66
|
+
});
|
|
67
|
+
await t.test('command looks like commit but result has no signature → false', () => {
|
|
68
|
+
const t1 = [bash('git commit -m "x"', 'c1'), result('c1', { text: 'ok' })].join('\n');
|
|
69
|
+
assert.equal(detectUncompletedCommit(t1), false);
|
|
70
|
+
});
|
|
71
|
+
await t.test('commit then complete_intent → false', () => {
|
|
72
|
+
const t1 = [bash('git commit -m "x"', 'c1'), result('c1', { text: COMMIT_OK }), toolUse(COMPLETE, 'k1'), result('k1')].join('\n');
|
|
73
|
+
assert.equal(detectUncompletedCommit(t1), false);
|
|
74
|
+
});
|
|
75
|
+
await t.test('complete then a NEW confirmed commit after it → true', () => {
|
|
76
|
+
const t1 = [
|
|
77
|
+
bash('git commit -m "a"', 'c1'), result('c1', { text: COMMIT_OK }),
|
|
78
|
+
toolUse(COMPLETE, 'k1'), result('k1'),
|
|
79
|
+
bash('git commit -m "b"', 'c2'), result('c2', { text: '[main 9f8e7d6] b\n 1 file changed' }),
|
|
80
|
+
].join('\n');
|
|
81
|
+
assert.equal(detectUncompletedCommit(t1), true);
|
|
82
|
+
});
|
|
83
|
+
await t.test('failed commit (is_error) → false', () => {
|
|
84
|
+
const t1 = [bash('git commit -m "x"', 'c1'), result('c1', { isError: true, text: 'fatal' })].join('\n');
|
|
85
|
+
assert.equal(detectUncompletedCommit(t1), false);
|
|
86
|
+
});
|
|
87
|
+
await t.test('"nothing to commit" → false', () => {
|
|
88
|
+
const t1 = [bash('git commit -m "x"', 'c1'), result('c1', { text: 'On branch main\nnothing to commit, working tree clean' })].join('\n');
|
|
89
|
+
assert.equal(detectUncompletedCommit(t1), false);
|
|
90
|
+
});
|
|
91
|
+
await t.test('attempted complete_intent (failed, conflicts) still suppresses the gate', () => {
|
|
92
|
+
// complete_intent was called after the commit even though it may have failed
|
|
93
|
+
// (conflicts) — the agent tried, so no nag.
|
|
94
|
+
const t1 = [
|
|
95
|
+
bash('git commit -m "x"', 'c1'), result('c1', { text: COMMIT_OK }),
|
|
96
|
+
toolUse(COMPLETE, 'k1'), result('k1', { text: '{ "success": false, "reason": "conflicts" }' }),
|
|
97
|
+
].join('\n');
|
|
98
|
+
assert.equal(detectUncompletedCommit(t1), false);
|
|
99
|
+
});
|
|
100
|
+
await t.test('garbage / non-JSON lines are skipped', () => {
|
|
101
|
+
const t1 = ['', 'not json', bash('git commit -m "x"', 'c1'), result('c1', { text: COMMIT_OK })].join('\n');
|
|
102
|
+
assert.equal(detectUncompletedCommit(t1), true);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
//# sourceMappingURL=uncompleted-commit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uncompleted-commit.test.js","sourceRoot":"","sources":["../../src/stop/uncompleted-commit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,10 +17,8 @@ export declare const activateIntentSchema: z.ZodObject<{
|
|
|
17
17
|
repoOrigin: z.ZodOptional<z.ZodString>;
|
|
18
18
|
repoPath: z.ZodString;
|
|
19
19
|
intentId: z.ZodString;
|
|
20
|
-
force: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
21
20
|
}, "strip", z.ZodTypeAny, {
|
|
22
21
|
repoPath: string;
|
|
23
|
-
force: boolean;
|
|
24
22
|
intentId: string;
|
|
25
23
|
repoOrigin?: string | undefined;
|
|
26
24
|
forkAuthor?: {
|
|
@@ -39,22 +37,14 @@ export declare const activateIntentSchema: z.ZodObject<{
|
|
|
39
37
|
forkOrigin: string;
|
|
40
38
|
} | undefined;
|
|
41
39
|
workspaceId?: string | undefined;
|
|
42
|
-
force?: boolean | undefined;
|
|
43
40
|
}>;
|
|
44
41
|
export type ActivateIntentInput = z.infer<typeof activateIntentSchema>;
|
|
45
|
-
export interface ActiveIntentLockConflict {
|
|
46
|
-
existingIntentId: string;
|
|
47
|
-
title?: string;
|
|
48
|
-
createdBy?: string;
|
|
49
|
-
author?: string;
|
|
50
|
-
}
|
|
51
42
|
export interface ActivateIntentResponse {
|
|
52
43
|
success: boolean;
|
|
53
44
|
intentId: string;
|
|
54
|
-
action?: 'activated' | 'already_active'
|
|
45
|
+
action?: 'activated' | 'already_active';
|
|
55
46
|
previousActiveId?: string;
|
|
56
47
|
message: string;
|
|
57
|
-
lockConflict?: ActiveIntentLockConflict;
|
|
58
48
|
}
|
|
59
49
|
export declare function activateIntent(input: ActivateIntentInput): Promise<ActivateIntentResponse>;
|
|
60
50
|
export declare const activateIntentTool: {
|
|
@@ -78,10 +68,8 @@ export declare const activateIntentTool: {
|
|
|
78
68
|
repoOrigin: z.ZodOptional<z.ZodString>;
|
|
79
69
|
repoPath: z.ZodString;
|
|
80
70
|
intentId: z.ZodString;
|
|
81
|
-
force: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
82
71
|
}, "strip", z.ZodTypeAny, {
|
|
83
72
|
repoPath: string;
|
|
84
|
-
force: boolean;
|
|
85
73
|
intentId: string;
|
|
86
74
|
repoOrigin?: string | undefined;
|
|
87
75
|
forkAuthor?: {
|
|
@@ -100,7 +88,6 @@ export declare const activateIntentTool: {
|
|
|
100
88
|
forkOrigin: string;
|
|
101
89
|
} | undefined;
|
|
102
90
|
workspaceId?: string | undefined;
|
|
103
|
-
force?: boolean | undefined;
|
|
104
91
|
}>;
|
|
105
92
|
handler: typeof activateIntent;
|
|
106
93
|
};
|
|
@@ -6,12 +6,11 @@ export const activateIntentSchema = z.object({
|
|
|
6
6
|
repoOrigin: z.string().optional().describe('Git remote origin URL. Auto-detected from repoPath via git if not provided.'),
|
|
7
7
|
repoPath: z.string().describe('Local path to the repository root'),
|
|
8
8
|
intentId: z.string().describe('The cloud ID (preferred) or local UUID of the existing intent to activate.'),
|
|
9
|
-
force: z.boolean().optional().default(false).describe('Bypass the per-repo active-intent lock. Set to true after the user has reviewed the lock conflict and chosen to take over.'),
|
|
10
9
|
...forkFieldsExtensions,
|
|
11
10
|
});
|
|
12
11
|
export async function activateIntent(input) {
|
|
13
12
|
const actualOrigin = resolveOrigin(input.repoOrigin, input.repoPath);
|
|
14
|
-
//
|
|
13
|
+
// This session's current focus before the switch.
|
|
15
14
|
const activeRes = await request('intent', 'get-active', { repoOrigin: actualOrigin });
|
|
16
15
|
const previousActiveId = activeRes.intentId || activeRes.intent?.id || '';
|
|
17
16
|
if (previousActiveId === input.intentId) {
|
|
@@ -20,88 +19,50 @@ export async function activateIntent(input) {
|
|
|
20
19
|
intentId: input.intentId,
|
|
21
20
|
action: 'already_active',
|
|
22
21
|
previousActiveId,
|
|
23
|
-
message: `Intent ${input.intentId.substring(0, 8)} is already
|
|
22
|
+
message: `Intent ${input.intentId.substring(0, 8)} is already your current intent`,
|
|
24
23
|
};
|
|
25
24
|
}
|
|
26
|
-
//
|
|
27
|
-
|
|
25
|
+
// Move THIS session's `current` pointer to the target intent. Under the
|
|
26
|
+
// multi-active model (no lock) this never conflicts — other sessions keep
|
|
27
|
+
// their own current pointers, and the API holds the full active set.
|
|
28
|
+
await request('intent', 'set-active', {
|
|
28
29
|
repoOrigin: actualOrigin,
|
|
29
30
|
intentId: input.intentId,
|
|
30
|
-
force: input.force || false,
|
|
31
31
|
...extractForkFields(input),
|
|
32
32
|
});
|
|
33
|
-
if (setRes.conflict === true && setRes.conflictType === 'active_intent_lock') {
|
|
34
|
-
const lockConflict = await buildLockConflictDetails(actualOrigin, setRes.existingIntentId);
|
|
35
|
-
const idShort = setRes.existingIntentId.substring(0, 8);
|
|
36
|
-
const who = lockConflict.author ? ` by ${lockConflict.author}` : '';
|
|
37
|
-
const titlePart = lockConflict.title ? ` "${lockConflict.title}"` : '';
|
|
38
|
-
return {
|
|
39
|
-
success: false,
|
|
40
|
-
intentId: input.intentId,
|
|
41
|
-
action: 'conflict',
|
|
42
|
-
lockConflict,
|
|
43
|
-
message: `Active-intent lock: repo already owns intent ${idShort}${titlePart}${who}. ` +
|
|
44
|
-
`Call activate_intent again with force=true to take over, complete_intent on ${idShort} first, ` +
|
|
45
|
-
`or choose a different intent.`,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
33
|
return {
|
|
49
34
|
success: true,
|
|
50
35
|
intentId: input.intentId,
|
|
51
36
|
action: 'activated',
|
|
52
37
|
previousActiveId: previousActiveId || undefined,
|
|
53
38
|
message: previousActiveId
|
|
54
|
-
? `
|
|
39
|
+
? `Switched current intent to ${input.intentId.substring(0, 8)} (was: ${previousActiveId.substring(0, 8)})`
|
|
55
40
|
: `Activated intent ${input.intentId.substring(0, 8)}`,
|
|
56
41
|
};
|
|
57
42
|
}
|
|
58
|
-
async function buildLockConflictDetails(repoOrigin, existingIntentId) {
|
|
59
|
-
try {
|
|
60
|
-
const res = await request('intent', 'get-active', { repoOrigin });
|
|
61
|
-
const intent = res.intent;
|
|
62
|
-
if (intent && intent.id === existingIntentId) {
|
|
63
|
-
return {
|
|
64
|
-
existingIntentId,
|
|
65
|
-
title: intent.title,
|
|
66
|
-
createdBy: intent.createdBy,
|
|
67
|
-
author: intent.authorInfo?.name || intent.author,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
catch {
|
|
72
|
-
// Fall through to ID-only response
|
|
73
|
-
}
|
|
74
|
-
return { existingIntentId };
|
|
75
|
-
}
|
|
76
43
|
export const activateIntentTool = {
|
|
77
44
|
name: 'activate_intent',
|
|
78
|
-
description: `Activate an existing intent by ID
|
|
45
|
+
description: `Activate an existing intent by ID — sets it as THIS session's current focus.
|
|
79
46
|
|
|
80
47
|
Use this to:
|
|
81
|
-
- Switch to a different intent found via list_team_intents or get_relevant_context
|
|
48
|
+
- Switch your current focus to a different intent found via list_team_intents or get_relevant_context
|
|
82
49
|
- Re-activate an intent that was deactivated (e.g., to complete it)
|
|
83
50
|
- Resume work on a previously created intent
|
|
84
|
-
- Resume an "abandoned"
|
|
51
|
+
- Resume an "abandoned" intent (see below)
|
|
85
52
|
|
|
86
53
|
Accepts both cloud IDs (from get_relevant_context / API) and local UUIDs (from list_team_intents).
|
|
87
54
|
|
|
88
|
-
|
|
55
|
+
Multi-active model: activating an intent only moves YOUR session's current
|
|
56
|
+
pointer. Many intents can be active on a repo at once (one current per
|
|
57
|
+
session/teammate), so this never blocks on or displaces another session's
|
|
58
|
+
active intent — there is no lock to take over.
|
|
59
|
+
|
|
60
|
+
Resuming abandoned intents:
|
|
89
61
|
- Abandoned intents have their decisions soft-deleted (invisible to recall and
|
|
90
62
|
get_relevant_context). Activating one transparently restores them — single-intent
|
|
91
63
|
decisions for this intent get their soft-delete cleared so the prior reasoning
|
|
92
64
|
becomes visible again. Multi-intent decisions stay visible throughout (they were
|
|
93
|
-
never soft-deleted)
|
|
94
|
-
- Pending intents are intents auto-finalized by the orphan-recovery sweeper (24h
|
|
95
|
-
inactivity) — possibly with conflicts blocking the finalization. Their decisions
|
|
96
|
-
were never soft-deleted, so activating one is a clean resume; new ephemerals
|
|
97
|
-
accumulate in a fresh bucket and the next complete_intent distills only the new work.
|
|
98
|
-
|
|
99
|
-
Per-repo active-intent lock: if another session already has a different intent active on
|
|
100
|
-
this repo, the tool returns action="conflict" with lockConflict details. Present the
|
|
101
|
-
conflict to the user and choose one of:
|
|
102
|
-
- Take over: retry with force=true (displaces the other session's active intent).
|
|
103
|
-
- Complete first: call complete_intent on the existing intent, then retry.
|
|
104
|
-
- Cancel: choose a different intent or stop.`,
|
|
65
|
+
never soft-deleted).`,
|
|
105
66
|
inputSchema: activateIntentSchema,
|
|
106
67
|
handler: activateIntent,
|
|
107
68
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activate-intent.js","sourceRoot":"","sources":["../../src/tools/activate-intent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAE3E,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6EAA6E,CAAC;IACzH,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;IAClE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4EAA4E,CAAC;IAC3G,
|
|
1
|
+
{"version":3,"file":"activate-intent.js","sourceRoot":"","sources":["../../src/tools/activate-intent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAE3E,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6EAA6E,CAAC;IACzH,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;IAClE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4EAA4E,CAAC;IAC3G,GAAG,oBAAoB;CACxB,CAAC,CAAA;AAYF,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAA0B;IAC7D,MAAM,YAAY,GAAG,aAAa,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;IAEpE,kDAAkD;IAClD,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,CAAA;IACrF,MAAM,gBAAgB,GAAG,SAAS,CAAC,QAAQ,IAAI,SAAS,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAA;IAEzE,IAAI,gBAAgB,KAAK,KAAK,CAAC,QAAQ,EAAE,CAAC;QACxC,OAAO;YACL,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,MAAM,EAAE,gBAAgB;YACxB,gBAAgB;YAChB,OAAO,EAAE,UAAU,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,iCAAiC;SACnF,CAAA;IACH,CAAC;IAED,wEAAwE;IACxE,0EAA0E;IAC1E,qEAAqE;IACrE,MAAM,OAAO,CAAC,QAAQ,EAAE,YAAY,EAAE;QACpC,UAAU,EAAE,YAAY;QACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,GAAG,iBAAiB,CAAC,KAAK,CAAC;KAC5B,CAAC,CAAA;IAEF,OAAO;QACL,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,WAAW;QACnB,gBAAgB,EAAE,gBAAgB,IAAI,SAAS;QAC/C,OAAO,EAAE,gBAAgB;YACvB,CAAC,CAAC,8BAA8B,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,gBAAgB,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;YAC3G,CAAC,CAAC,oBAAoB,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;KACzD,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,IAAI,EAAE,iBAAiB;IACvB,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;uBAoBQ;IACrB,WAAW,EAAE,oBAAoB;IACjC,OAAO,EAAE,cAAc;CACxB,CAAA"}
|