kushi-agents 3.12.1 → 3.13.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/.github/copilot-instructions.kushi.md +38 -0
- package/bin/cli.mjs +2 -0
- package/package.json +3 -2
- package/src/copilot-instructions.mjs +80 -0
- package/src/main.mjs +18 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
## Kushi — Project Evidence Agent
|
|
2
|
+
|
|
3
|
+
This workspace has [Kushi](https://gim-home.github.io/kushi/) installed under `.kushi/`. Kushi captures multi-source project evidence (Email, Teams, OneNote, SharePoint, Meetings, CRM, ADO) via **WorkIQ** and answers cited questions over the captured evidence.
|
|
4
|
+
|
|
5
|
+
### Routing — no `@Kushi` prefix required
|
|
6
|
+
|
|
7
|
+
When the user types any of the following verbs followed by a project name, route to the corresponding Kushi prompt in `.kushi/prompts/` (no `@Kushi` needed):
|
|
8
|
+
|
|
9
|
+
| Verb | Prompt to run |
|
|
10
|
+
| -------------------------- | ------------------------------------------ |
|
|
11
|
+
| `bootstrap <project>` | `/pull-all-bootstrap` |
|
|
12
|
+
| `refresh <project>` | `/pull-all-refresh` |
|
|
13
|
+
| `aggregate <project>` | `/pull-all-aggregate` |
|
|
14
|
+
| `state <project>` | `/rebuild-state` |
|
|
15
|
+
| `consolidate <project>` | `/consolidate-evidence` |
|
|
16
|
+
| `status <project>` | `/show-run-log` |
|
|
17
|
+
| `ask <project> <question>` | `/ask-project` (auto-routes to evidence Q&A) |
|
|
18
|
+
|
|
19
|
+
Project Q&A also auto-dispatches when the user names a known project under the engagement root **and** asks a question about it — no prefix needed.
|
|
20
|
+
|
|
21
|
+
### Hard rules (enforced by Kushi skills)
|
|
22
|
+
|
|
23
|
+
- **WorkIQ-first** for all M365 sources. `m365_*` / Microsoft Graph calls are only allowed as a classified fallback after a documented WorkIQ failure.
|
|
24
|
+
- **Every assertion** in any Kushi output (State files, Evidence summaries, consolidated reports, Open Questions) MUST carry an inline citation: `[source: <alias>/<folder>/<file> · YYYY-MM-DD]`.
|
|
25
|
+
- **Read-only Q&A** — `ask` never triggers any `pull-*` skill. Stale evidence (>14d) prompts the user to refresh; Kushi does not auto-refresh.
|
|
26
|
+
- **No cross-project bleed** — answers must be grounded only in the named project's `Evidence/` + `State/` + `snapshot/`.
|
|
27
|
+
- **Never reach out** — Kushi does not send Teams/email/CRM-note/ADO-comment on the user's behalf unless they explicitly request it that turn. Recommendations go into the project's Open Questions, not into outbound sends.
|
|
28
|
+
|
|
29
|
+
### Layout
|
|
30
|
+
|
|
31
|
+
- `.kushi/agents/kushi.agent.md` — orchestrator (also addressable as `@Kushi`)
|
|
32
|
+
- `.kushi/prompts/` — verb prompts (`/pull-*`, `/ask-project`, etc.)
|
|
33
|
+
- `.kushi/skills/` — per-source pull + render skills
|
|
34
|
+
- `.kushi/instructions/` — doctrine (citations, WorkIQ-first, freshness gates)
|
|
35
|
+
- `.kushi/reference-packs/` — bundled domain doctrine (override at project / user / packaged layers)
|
|
36
|
+
- `.kushi/kushi-install.json` — profile manifest written by the installer
|
|
37
|
+
|
|
38
|
+
Full docs: <https://gim-home.github.io/kushi/>
|
package/bin/cli.mjs
CHANGED
|
@@ -26,6 +26,7 @@ if (args.includes('--help') || args.includes('-h')) {
|
|
|
26
26
|
--dest <path> Override destination (relative for vscode, absolute for clawpilot)
|
|
27
27
|
--force Overwrite existing destination without asking
|
|
28
28
|
--no-settings Skip .vscode/settings.json update (vscode target only)
|
|
29
|
+
--no-instructions Skip .github/copilot-instructions.md merge (vscode target only)
|
|
29
30
|
--help, -h Show this help
|
|
30
31
|
|
|
31
32
|
After install, talk to Kushi:
|
|
@@ -55,6 +56,7 @@ const options = {
|
|
|
55
56
|
dest: getFlag('--dest'),
|
|
56
57
|
force: args.includes('--force'),
|
|
57
58
|
noSettings: args.includes('--no-settings'),
|
|
59
|
+
noInstructions: args.includes('--no-instructions'),
|
|
58
60
|
target,
|
|
59
61
|
profile: getFlag('--profile'),
|
|
60
62
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kushi-agents",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.13.0",
|
|
4
4
|
"description": "Install Kushi — multi-source project evidence agent with snapshot+stream capture across Email, Teams, OneNote, SharePoint, Meetings, CRM, ADO. WorkIQ-only for M365 sources (Graph / m365_* FORBIDDEN as fallbacks; user-paste is first-class). Host-agnostic.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"src/",
|
|
12
12
|
"plugin/",
|
|
13
13
|
".github/config/m365-auth.json.example",
|
|
14
|
-
".github/config/m365-mutable.json.example"
|
|
14
|
+
".github/config/m365-mutable.json.example",
|
|
15
|
+
".github/copilot-instructions.kushi.md"
|
|
15
16
|
],
|
|
16
17
|
"engines": {
|
|
17
18
|
"node": ">=18.0.0"
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
export const KUSHI_BEGIN_MARKER = '<!-- BEGIN kushi-agents (managed — do not edit between markers) -->';
|
|
5
|
+
export const KUSHI_END_MARKER = '<!-- END kushi-agents -->';
|
|
6
|
+
|
|
7
|
+
const MARKER_REGEX = new RegExp(
|
|
8
|
+
`${escapeRegex(KUSHI_BEGIN_MARKER)}[\\s\\S]*?${escapeRegex(KUSHI_END_MARKER)}`,
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
function escapeRegex(str) {
|
|
12
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Wrap the source content in our managed-block markers.
|
|
17
|
+
* @param {string} source
|
|
18
|
+
* @returns {string}
|
|
19
|
+
*/
|
|
20
|
+
function buildBlock(source) {
|
|
21
|
+
return `${KUSHI_BEGIN_MARKER}\n${source.trim()}\n${KUSHI_END_MARKER}\n`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Merge the Kushi section into .github/copilot-instructions.md using
|
|
26
|
+
* managed-block markers. Three behaviors:
|
|
27
|
+
*
|
|
28
|
+
* - File missing → create it with a brief header + our block
|
|
29
|
+
* - File has markers → replace block content in place (idempotent upgrade)
|
|
30
|
+
* - File without markers → append our block at the end, preserving user content
|
|
31
|
+
*
|
|
32
|
+
* @param {string} projectRoot
|
|
33
|
+
* @param {string} sourcePkgDir – root of the npm package (for reading the source template)
|
|
34
|
+
* @returns {{ action: 'created' | 'updated-block' | 'appended-block' | 'unchanged', path: string }}
|
|
35
|
+
*/
|
|
36
|
+
export function mergeCopilotInstructions(projectRoot, sourcePkgDir) {
|
|
37
|
+
const srcTemplate = path.join(
|
|
38
|
+
sourcePkgDir,
|
|
39
|
+
'.github',
|
|
40
|
+
'copilot-instructions.kushi.md',
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if (!fs.existsSync(srcTemplate)) {
|
|
44
|
+
return { action: 'unchanged', path: '', reason: 'source template missing' };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const sourceContent = fs.readFileSync(srcTemplate, 'utf-8');
|
|
48
|
+
const block = buildBlock(sourceContent);
|
|
49
|
+
|
|
50
|
+
const githubDir = path.join(projectRoot, '.github');
|
|
51
|
+
const targetPath = path.join(githubDir, 'copilot-instructions.md');
|
|
52
|
+
const displayPath = '.github/copilot-instructions.md';
|
|
53
|
+
|
|
54
|
+
fs.mkdirSync(githubDir, { recursive: true });
|
|
55
|
+
|
|
56
|
+
if (!fs.existsSync(targetPath)) {
|
|
57
|
+
const header = `# Copilot Instructions\n\n_This file is auto-loaded by GitHub Copilot Chat into every chat turn in this workspace._\n\n`;
|
|
58
|
+
fs.writeFileSync(targetPath, header + block, 'utf-8');
|
|
59
|
+
return { action: 'created', path: displayPath };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const existing = fs.readFileSync(targetPath, 'utf-8');
|
|
63
|
+
|
|
64
|
+
if (MARKER_REGEX.test(existing)) {
|
|
65
|
+
const updated = existing.replace(MARKER_REGEX, block.trimEnd());
|
|
66
|
+
if (updated === existing) {
|
|
67
|
+
return { action: 'unchanged', path: displayPath };
|
|
68
|
+
}
|
|
69
|
+
fs.writeFileSync(targetPath, updated, 'utf-8');
|
|
70
|
+
return { action: 'updated-block', path: displayPath };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const separator = existing.endsWith('\n\n')
|
|
74
|
+
? ''
|
|
75
|
+
: existing.endsWith('\n')
|
|
76
|
+
? '\n'
|
|
77
|
+
: '\n\n';
|
|
78
|
+
fs.writeFileSync(targetPath, existing + separator + block, 'utf-8');
|
|
79
|
+
return { action: 'appended-block', path: displayPath };
|
|
80
|
+
}
|
package/src/main.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { promptForDestination } from './prompt.mjs';
|
|
15
15
|
import { copyAssets, copyProjectFiles } from './copy-assets.mjs';
|
|
16
16
|
import { mergeSettings } from './settings.mjs';
|
|
17
|
+
import { mergeCopilotInstructions } from './copilot-instructions.mjs';
|
|
17
18
|
import {
|
|
18
19
|
resolveProfile,
|
|
19
20
|
makeIncludeFilter,
|
|
@@ -48,7 +49,7 @@ function resolveProfileForInstall(profileName) {
|
|
|
48
49
|
|
|
49
50
|
/**
|
|
50
51
|
* Orchestrator: prompt -> copy -> settings -> summary.
|
|
51
|
-
* @param {{ dest?: string, force?: boolean, noSettings?: boolean, target?: string, profile?: string }} options
|
|
52
|
+
* @param {{ dest?: string, force?: boolean, noSettings?: boolean, noInstructions?: boolean, target?: string, profile?: string }} options
|
|
52
53
|
*/
|
|
53
54
|
export async function main(options = {}) {
|
|
54
55
|
const version = getVersion();
|
|
@@ -150,6 +151,22 @@ async function installVscode(options, resolved, version) {
|
|
|
150
151
|
console.log('\n Skipped .vscode/settings.json (--no-settings)');
|
|
151
152
|
}
|
|
152
153
|
|
|
154
|
+
if (!options.noInstructions) {
|
|
155
|
+
const result = mergeCopilotInstructions(projectRoot, PKG_ROOT);
|
|
156
|
+
const labelByAction = {
|
|
157
|
+
'created': 'Created',
|
|
158
|
+
'updated-block': 'Updated managed Kushi block in',
|
|
159
|
+
'appended-block': 'Appended managed Kushi block to existing',
|
|
160
|
+
'unchanged': 'Unchanged',
|
|
161
|
+
};
|
|
162
|
+
if (result.action !== 'unchanged' || result.path) {
|
|
163
|
+
const label = labelByAction[result.action] || 'Touched';
|
|
164
|
+
console.log(`\n ${label} ${result.path}`);
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
console.log('\n Skipped .github/copilot-instructions.md (--no-instructions)');
|
|
168
|
+
}
|
|
169
|
+
|
|
153
170
|
const { copied: projCopied, skipped: projSkipped } = copyProjectFiles(PKG_ROOT);
|
|
154
171
|
if (projCopied.length > 0) {
|
|
155
172
|
console.log('\n Copied project files to .github/');
|