kushi-agents 4.4.3 → 4.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/package.json +4 -4
- package/plugin/agents/kushi.agent.md +30 -14
- package/plugin/config/studios.json +37 -0
- package/plugin/config/studios.schema.json +45 -0
- package/plugin/instructions/auth-and-retry.instructions.md +268 -1
- package/plugin/instructions/engagement-root-resolution.instructions.md +5 -1
- package/plugin/instructions/evidence-thoroughness.instructions.md +103 -1
- package/plugin/instructions/fuzzy-disambiguation.instructions.md +97 -0
- package/plugin/instructions/identity-resolution.instructions.md +76 -0
- package/plugin/instructions/issue-recovery.instructions.md +58 -0
- package/plugin/instructions/kushi-config-root.instructions.md +66 -0
- package/plugin/instructions/loop-bootstrap-discovery.instructions.md +105 -0
- package/plugin/instructions/m365-id-registry.instructions.md +1 -1
- package/plugin/instructions/onedrive-pin-policy.instructions.md +132 -0
- package/plugin/instructions/per-source-verification-gate.instructions.md +193 -0
- package/plugin/instructions/sharepoint-to-onedrive-sync.instructions.md +116 -0
- package/plugin/instructions/status-color-rule.instructions.md +62 -0
- package/plugin/instructions/studio-registry.instructions.md +48 -0
- package/plugin/instructions/update-ledger.instructions.md +1 -1
- package/plugin/instructions/verbatim-by-default.instructions.md +1 -1
- package/plugin/instructions/vertex-emit.instructions.md +120 -0
- package/plugin/instructions/workiq-input-sanitization.instructions.md +43 -0
- package/plugin/instructions/workiq-onenote-query-shape.instructions.md +79 -0
- package/plugin/instructions/workiq-only.instructions.md +15 -9
- package/plugin/learnings/loop.md +11 -0
- package/plugin/learnings/onenote.md +27 -1
- package/plugin/lib/Get-KushiConfig.ps1 +22 -9
- package/plugin/lib/detect-vertex-repo.mjs +96 -0
- package/plugin/lib/render-vertex.mjs +249 -0
- package/plugin/lib/sanitize-workiq-input.mjs +72 -0
- package/plugin/lib/studio-registry.mjs +39 -0
- package/plugin/lib/vertex-validate.mjs +121 -0
- package/plugin/plugin.json +16 -6
- package/plugin/prompts/bootstrap.prompt.md +9 -7
- package/plugin/prompts/emit-vertex.prompt.md +33 -0
- package/plugin/prompts/setup.prompt.md +29 -0
- package/plugin/prompts/vertex-link.prompt.md +27 -0
- package/plugin/skills/aggregate-project/SKILL.md +24 -2
- package/plugin/skills/apply-ado-update/SKILL.md +9 -4
- package/plugin/skills/ask-project/SKILL.md +4 -0
- package/plugin/skills/bootstrap-project/SKILL.md +67 -41
- package/plugin/skills/consolidate-evidence/SKILL.md +5 -1
- package/plugin/skills/emit-vertex/README.md +37 -0
- package/plugin/skills/emit-vertex/SKILL.md +173 -0
- package/plugin/skills/intro/SKILL.md +2 -0
- package/plugin/skills/propose-ado-update/SKILL.md +8 -3
- package/plugin/skills/pull-ado/SKILL.md +11 -1
- package/plugin/skills/pull-crm/SKILL.md +12 -2
- package/plugin/skills/pull-email/SKILL.md +11 -1
- package/plugin/skills/pull-loop/README.md +64 -0
- package/plugin/skills/pull-loop/SKILL.md +180 -0
- package/plugin/skills/pull-loop/runner.mjs +261 -0
- package/plugin/skills/pull-loop/write-snapshot.mjs +181 -0
- package/plugin/skills/pull-meetings/SKILL.md +11 -1
- package/plugin/skills/pull-misc/README.md +4 -4
- package/plugin/skills/pull-misc/SKILL.md +18 -12
- package/plugin/skills/pull-onenote/SKILL.md +71 -19
- package/plugin/skills/pull-sharepoint/SKILL.md +11 -2
- package/plugin/skills/pull-teams/SKILL.md +11 -2
- package/plugin/skills/refresh-project/SKILL.md +38 -7
- package/plugin/skills/self-check/SKILL.md +14 -1
- package/plugin/skills/self-check/run.ps1 +442 -20
- package/plugin/skills/setup/SKILL.md +377 -0
- package/plugin/skills/vertex-link/SKILL.md +143 -0
- package/plugin/templates/init/m365-auth.template.json +10 -4
- package/plugin/templates/init/project-evidence.template.yml +10 -3
- package/plugin/templates/init/project-integrations.template.yml +5 -0
- package/plugin/templates/snapshot/ado-item.template.md +1 -1
- package/plugin/templates/snapshot/crm-record.template.md +1 -1
- package/plugin/templates/snapshot/meetings-series-index.template.md +1 -1
- package/plugin/templates/snapshot/onenote-page.template.md +1 -1
- package/plugin/templates/snapshot/sharepoint-file.template.md +1 -1
- package/plugin/templates/snapshot/sharepoint-tree.template.md +1 -1
- package/plugin/templates/snapshot/teams-roster.template.md +1 -1
- package/plugin/templates/weekly/ado-stream.template.md +1 -1
- package/plugin/templates/weekly/crm-stream.template.md +1 -1
- package/plugin/templates/weekly/email-stream.template.md +1 -1
- package/plugin/templates/weekly/meetings-stream.template.md +1 -1
- package/plugin/templates/weekly/onenote-stream.template.md +1 -1
- package/plugin/templates/weekly/sharepoint-stream.template.md +1 -1
- package/plugin/templates/weekly/teams-stream.template.md +1 -1
- package/src/check-workiq.mjs +109 -15
- package/src/config-loader.mjs +71 -13
- package/src/config-root-resolve.test.mjs +137 -0
- package/src/detect-vertex-repo.test.mjs +128 -0
- package/src/emit-vertex.e2e.test.mjs +308 -0
- package/src/forbidden-workiq-phrasings.test.mjs +111 -0
- package/src/main.mjs +11 -2
- package/src/sanitize-workiq-input.test.mjs +45 -0
- package/src/vertex-validate.test.mjs +142 -0
- package/plugin/instructions/az-auth-conditional.instructions.md +0 -39
- package/plugin/instructions/azure-auth-patterns.instructions.md +0 -233
- package/plugin/instructions/thoroughness-detector.instructions.md +0 -105
- package/plugin/instructions/workiq-first.instructions.md +0 -31
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// pull-loop write-snapshot wrapper. Drives runner.mjs, writes canonical layout, upserts
|
|
3
|
+
// m365-mutable.json#knownSections.<project>.loop.workspaces[].loop_pages[], emits run report.
|
|
4
|
+
// Per pull-loop SKILL.md v1.0.0.
|
|
5
|
+
|
|
6
|
+
import { spawnSync } from 'node:child_process';
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import process from 'node:process';
|
|
10
|
+
|
|
11
|
+
const args = Object.fromEntries(
|
|
12
|
+
process.argv.slice(2).reduce((acc, cur, idx, arr) => {
|
|
13
|
+
if (cur.startsWith('--')) {
|
|
14
|
+
const key = cur.replace(/^--/, '');
|
|
15
|
+
const next = arr[idx + 1];
|
|
16
|
+
acc.push([key, next && !next.startsWith('--') ? next : true]);
|
|
17
|
+
}
|
|
18
|
+
return acc;
|
|
19
|
+
}, [])
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const PROJECT = args.project;
|
|
23
|
+
const WORKSPACE_URL = args['workspace-url'];
|
|
24
|
+
const ENG_ROOT = args['engagement-root'];
|
|
25
|
+
const ALIAS = args.alias;
|
|
26
|
+
const HEADLESS = !!args.headless;
|
|
27
|
+
const TITLES = args.titles || null;
|
|
28
|
+
|
|
29
|
+
if (!PROJECT || !WORKSPACE_URL || !ENG_ROOT || !ALIAS) {
|
|
30
|
+
console.error('Usage: --project <name> --workspace-url <url> --engagement-root <path> --alias <alias> [--headless] [--titles "a,b"]');
|
|
31
|
+
process.exit(2);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const slugify = (s) => String(s || '').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 80) || 'untitled';
|
|
35
|
+
const isoStamp = () => new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
36
|
+
|
|
37
|
+
const runnerArgs = ['plugin/skills/pull-loop/runner.mjs', '--project', PROJECT, '--workspace-url', WORKSPACE_URL];
|
|
38
|
+
if (HEADLESS) runnerArgs.push('--headless');
|
|
39
|
+
if (TITLES) runnerArgs.push('--titles', TITLES);
|
|
40
|
+
|
|
41
|
+
const result = spawnSync(process.execPath, runnerArgs, { encoding: 'utf8' });
|
|
42
|
+
let payload;
|
|
43
|
+
try {
|
|
44
|
+
payload = JSON.parse(result.stdout || '{}');
|
|
45
|
+
} catch {
|
|
46
|
+
console.error('Runner did not return JSON. stderr:\n' + result.stderr);
|
|
47
|
+
process.exit(5);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const { pages = [], runStatus = 'workspace-unavailable', authRequiredCount = 0, preflight } = payload;
|
|
51
|
+
|
|
52
|
+
function workspaceSlugFromUrl(url) {
|
|
53
|
+
try {
|
|
54
|
+
const m = String(url).match(/\/loop\/p\/([^/]+)/i);
|
|
55
|
+
return slugify((m && m[1]) || 'workspace');
|
|
56
|
+
} catch { return 'workspace'; }
|
|
57
|
+
}
|
|
58
|
+
const wsSlug = workspaceSlugFromUrl(WORKSPACE_URL);
|
|
59
|
+
|
|
60
|
+
const snapDir = path.join(ENG_ROOT, PROJECT, 'Evidence', ALIAS, 'loop', 'snapshot', wsSlug);
|
|
61
|
+
fs.mkdirSync(snapDir, { recursive: true });
|
|
62
|
+
|
|
63
|
+
const workspaceMd = [
|
|
64
|
+
'---',
|
|
65
|
+
`source: loop`,
|
|
66
|
+
`project: ${PROJECT}`,
|
|
67
|
+
`workspace_url: ${WORKSPACE_URL}`,
|
|
68
|
+
`captured_at: ${new Date().toISOString()}`,
|
|
69
|
+
`evidence_source_kind: tree-only`,
|
|
70
|
+
'---',
|
|
71
|
+
'',
|
|
72
|
+
`# Loop workspace — ${wsSlug}`,
|
|
73
|
+
'',
|
|
74
|
+
`Source URL: ${WORKSPACE_URL}`,
|
|
75
|
+
`Captured: ${new Date().toISOString()}`,
|
|
76
|
+
`Pages enumerated: ${pages.length}`,
|
|
77
|
+
'',
|
|
78
|
+
'## Pages',
|
|
79
|
+
'',
|
|
80
|
+
...pages.map(p => `- [${p.pageTitle || '(untitled)'}](${p.pageUrl}) — last_status: \`${p.last_status}\``),
|
|
81
|
+
''
|
|
82
|
+
].join('\n');
|
|
83
|
+
fs.writeFileSync(path.join(snapDir, '_workspace.md'), workspaceMd, 'utf8');
|
|
84
|
+
|
|
85
|
+
for (const p of pages) {
|
|
86
|
+
const pSlug = slugify(p.pageTitle || p.pageUrl);
|
|
87
|
+
const md = [
|
|
88
|
+
'---',
|
|
89
|
+
`source: loop`,
|
|
90
|
+
`project: ${PROJECT}`,
|
|
91
|
+
`workspace_url: ${WORKSPACE_URL}`,
|
|
92
|
+
`page_url: ${p.pageUrl}`,
|
|
93
|
+
`page_title: ${JSON.stringify(p.pageTitle || '')}`,
|
|
94
|
+
`captured_at: ${p.capturedAt || new Date().toISOString()}`,
|
|
95
|
+
`captured_via: ${p.captured_via || 'playwright'}`,
|
|
96
|
+
`last_status: ${p.last_status}`,
|
|
97
|
+
`evidence_source_kind: ${p.evidence_source_kind || (p.bodyLen > 0 ? 'page-body' : 'page-body-unavailable')}`,
|
|
98
|
+
'---',
|
|
99
|
+
'',
|
|
100
|
+
`# ${p.pageTitle || '(untitled)'}`,
|
|
101
|
+
'',
|
|
102
|
+
`Source: ${p.pageUrl}`,
|
|
103
|
+
'',
|
|
104
|
+
p.body || '_(body unavailable — see coverage notes)_',
|
|
105
|
+
''
|
|
106
|
+
].join('\n');
|
|
107
|
+
fs.writeFileSync(path.join(snapDir, `${pSlug}.md`), md, 'utf8');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function findMutableJson() {
|
|
111
|
+
const candidates = [
|
|
112
|
+
path.resolve('.kushi', 'config', 'user', 'm365-mutable.json'),
|
|
113
|
+
path.join(process.env.USERPROFILE || process.env.HOME || '', '.copilot', 'm-skills', 'kushi', 'config', 'user', 'm365-mutable.json')
|
|
114
|
+
];
|
|
115
|
+
for (const c of candidates) {
|
|
116
|
+
if (fs.existsSync(c)) return c;
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const mutPath = findMutableJson();
|
|
122
|
+
if (mutPath) {
|
|
123
|
+
try {
|
|
124
|
+
const mut = JSON.parse(fs.readFileSync(mutPath, 'utf8'));
|
|
125
|
+
mut.knownSections = mut.knownSections || {};
|
|
126
|
+
mut.knownSections[PROJECT] = mut.knownSections[PROJECT] || {};
|
|
127
|
+
mut.knownSections[PROJECT].loop = mut.knownSections[PROJECT].loop || { workspaces: [] };
|
|
128
|
+
let ws = mut.knownSections[PROJECT].loop.workspaces.find(w => w.workspaceUrl === WORKSPACE_URL);
|
|
129
|
+
if (!ws) {
|
|
130
|
+
ws = { workspaceUrl: WORKSPACE_URL, loop_pages: [] };
|
|
131
|
+
mut.knownSections[PROJECT].loop.workspaces.push(ws);
|
|
132
|
+
}
|
|
133
|
+
ws.loop_pages = ws.loop_pages || [];
|
|
134
|
+
for (const p of pages) {
|
|
135
|
+
let existing = ws.loop_pages.find(x => x.pageUrl === p.pageUrl);
|
|
136
|
+
if (!existing) {
|
|
137
|
+
existing = { pageUrl: p.pageUrl };
|
|
138
|
+
ws.loop_pages.push(existing);
|
|
139
|
+
}
|
|
140
|
+
existing.pageTitle = p.pageTitle || existing.pageTitle;
|
|
141
|
+
existing.last_status = p.last_status;
|
|
142
|
+
existing.last_captured_at = p.capturedAt;
|
|
143
|
+
existing.captured_via = p.captured_via;
|
|
144
|
+
}
|
|
145
|
+
fs.writeFileSync(mutPath, JSON.stringify(mut, null, 2), 'utf8');
|
|
146
|
+
} catch (e) {
|
|
147
|
+
console.error('Upsert m365-mutable.json failed:', e?.message || e);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const reportDir = path.join(ENG_ROOT, PROJECT, 'Evidence', ALIAS, 'refresh-reports');
|
|
152
|
+
fs.mkdirSync(reportDir, { recursive: true });
|
|
153
|
+
const reportPath = path.join(reportDir, `${isoStamp()}_loop.md`);
|
|
154
|
+
const okCount = pages.filter(p => p.last_status === 'ok').length;
|
|
155
|
+
const report = [
|
|
156
|
+
`# pull-loop run — ${PROJECT} — ${new Date().toISOString()}`,
|
|
157
|
+
'',
|
|
158
|
+
`Workspace: ${WORKSPACE_URL}`,
|
|
159
|
+
`Run status: \`${runStatus}\``,
|
|
160
|
+
`Pages: ${pages.length} (ok: ${okCount}; auth-required: ${authRequiredCount})`,
|
|
161
|
+
preflight ? `Preflight: ${JSON.stringify(preflight)}` : '',
|
|
162
|
+
'',
|
|
163
|
+
'## Per-page outcomes',
|
|
164
|
+
'',
|
|
165
|
+
'| Title | Status | Source-kind | Bytes |',
|
|
166
|
+
'|---|---|---|---:|',
|
|
167
|
+
...pages.map(p => `| ${(p.pageTitle || '(untitled)').replace(/\|/g, '\\|')} | ${p.last_status} | ${p.evidence_source_kind} | ${p.bodyLen || 0} |`),
|
|
168
|
+
''
|
|
169
|
+
].filter(Boolean).join('\n');
|
|
170
|
+
fs.writeFileSync(reportPath, report, 'utf8');
|
|
171
|
+
|
|
172
|
+
console.log(JSON.stringify({
|
|
173
|
+
project: PROJECT,
|
|
174
|
+
workspaceUrl: WORKSPACE_URL,
|
|
175
|
+
snapshotDir: snapDir,
|
|
176
|
+
reportPath,
|
|
177
|
+
runStatus,
|
|
178
|
+
pagesWritten: pages.length,
|
|
179
|
+
okCount,
|
|
180
|
+
authRequiredCount
|
|
181
|
+
}, null, 2));
|
|
@@ -23,7 +23,7 @@ Pulls **meetings** evidence in three shapes per `snapshot-vs-stream.instructions
|
|
|
23
23
|
- **stream/** — per-meeting curated blocks: attendees (req/opt/actual), agenda, **chronological transcript walk-through with verbatim quotes + timestamps**, decisions, actions, open questions, artifact links. Each block MUST cite the matching verbatim/ folder.
|
|
24
24
|
- **verbatim/** (REQUIRED, NEW v2.2.0) — per-meeting subfolder `verbatim/<YYYY-MM-DD-HHMM>_<slug>/` containing the raw immutable capture: `captured-at.txt`, `chat-messages.json`, `chat-messages.md`, `transcript.vtt` or `transcript-source.md`, `recording-url.txt`, `recap-card.md`, `attachments/`, `coverage.md`. See `templates/snapshot/meeting-verbatim.template.md` for the contract.
|
|
25
25
|
|
|
26
|
-
Auth + retry + error logging per `auth-and-retry.instructions.md`. WorkIQ-only per `workiq-only.instructions.md`. Thoroughness per `evidence-thoroughness.instructions.md`; runtime detector + auto-retry + paste-prompt per `thoroughness
|
|
26
|
+
Auth + retry + error logging per `auth-and-retry.instructions.md`. WorkIQ-only per `workiq-only.instructions.md`. Thoroughness per `evidence-thoroughness.instructions.md`; runtime detector + auto-retry + paste-prompt per `evidence-thoroughness.instructions.md`. Citations per `citation-ledger.instructions.md`.
|
|
27
27
|
|
|
28
28
|
## Inputs
|
|
29
29
|
|
|
@@ -159,3 +159,13 @@ After the pass:
|
|
|
159
159
|
- A meeting has neither transcript NOR chat messages → write `verbatim/<dir>/coverage.md` documenting every failed path + write `❌ source-expired-or-unrecoverable` block in stream/, log error, continue.
|
|
160
160
|
- All paths failed for ALL meetings in the window → mark source `failed`, write a single `❌ all paths failed` evidence file with actionable next step. Verbatim/ folders for each meeting still get created with captured-at.txt + coverage.md (the empty-folder audit trail is itself evidence).
|
|
161
161
|
- A per-meeting block lacks a sibling `verbatim/<YYYY-MM-DD-HHMM>_<slug>/` directory → **defect** per `meetings-verbatim-required.instructions.md`. Re-run Half A immediately; do NOT ship the curated block alone.
|
|
162
|
+
|
|
163
|
+
## References (v4.4.7)
|
|
164
|
+
|
|
165
|
+
- Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
|
|
166
|
+
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
## Issue Recovery
|
|
170
|
+
|
|
171
|
+
When this skill exposes a reusable defect (auth pattern, doctrine gap, layout mismatch), apply the [Issue Recovery Rule](../../instructions/issue-recovery.instructions.md): fix the smallest correct repo-owned artifact first, prefer durable fixes over per-run workarounds, then re-run the narrowest failed check. Do NOT use memory as a substitute for correcting the workflow surface.
|
|
@@ -8,7 +8,7 @@ See `SKILL.md` for the full doctrine.
|
|
|
8
8
|
|
|
9
9
|
```pwsh
|
|
10
10
|
# Install deps in the kushi repo
|
|
11
|
-
cd
|
|
11
|
+
cd <kushi-repo-root>
|
|
12
12
|
npm install playwright jsdom @mozilla/readability
|
|
13
13
|
npx playwright install chromium
|
|
14
14
|
|
|
@@ -21,9 +21,9 @@ node plugin/skills/pull-onenote/runner.mjs --bootstrap
|
|
|
21
21
|
|
|
22
22
|
```pwsh
|
|
23
23
|
node plugin/skills/pull-misc/runner.mjs `
|
|
24
|
-
--project "
|
|
25
|
-
--links-file "
|
|
26
|
-
--engagement-root "
|
|
24
|
+
--project "<project>" `
|
|
25
|
+
--links-file "<engagement-root>/<project>/external-links.txt" `
|
|
26
|
+
--engagement-root "<engagement-root>" `
|
|
27
27
|
--headless
|
|
28
28
|
```
|
|
29
29
|
|
|
@@ -12,7 +12,7 @@ description: "Pull miscellaneous evidence from a user-curated link list (<projec
|
|
|
12
12
|
> - `capture-learnings.instructions.md` — every fix/discovery is logged to `plugin/learnings/misc.md`.
|
|
13
13
|
> - `cleanup-on-resolution.instructions.md` — when a placeholder URL resolves, all stale unavailable-markers are upgraded in the same turn.
|
|
14
14
|
> - `run-reports.instructions.md` — every refresh writes a per-user report under `Evidence/<alias>/refresh-reports/`.
|
|
15
|
-
> - `thoroughness
|
|
15
|
+
> - `evidence-thoroughness.instructions.md` — the per-link retry registry IS this skill's thoroughness contract.
|
|
16
16
|
|
|
17
17
|
> **Canonical evidence layout** (HARD, kushi v3.12.1+): all artifacts produced by this skill MUST be written under `<project>/Evidence/<alias>/<source>/{snapshot,stream,...}/` — sibling folders under `<project>/` (e.g. `<project>/<source>-context/`, `<project>/<source>/`, `<project>/_Weekly Summaries/`) are FORBIDDEN. See `evidence-layout-canonical.instructions.md`.
|
|
18
18
|
|
|
@@ -48,7 +48,7 @@ Format:
|
|
|
48
48
|
| `onenote` | pull-onenote | delegated |
|
|
49
49
|
| `sharepoint` | pull-sharepoint | delegated |
|
|
50
50
|
| `ado` | pull-ado | delegated |
|
|
51
|
-
| `loop`
|
|
51
|
+
| `loop` | pull-loop | delegated (v4.6.0+ — was inline-browser in v3.9.0–v4.5.x) |
|
|
52
52
|
| `web` | pull-misc | http (fetch + readability) |
|
|
53
53
|
| `confluence` | pull-misc | http (anonymous) — auth'd Confluence not yet supported |
|
|
54
54
|
| `learn` | pull-misc | http |
|
|
@@ -105,15 +105,11 @@ For each project, the bootstrap step:
|
|
|
105
105
|
|
|
106
106
|
The runner branches per `type`:
|
|
107
107
|
|
|
108
|
-
### B.1 `loop` —
|
|
108
|
+
### B.1 `loop` — delegate (v4.6.0+)
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
// pages.goto(loopUrl); detect login redirect → auth-required.
|
|
112
|
-
// Wait for primary canvas selector; for Loop, that's the Fluid container.
|
|
113
|
-
// Read text via document.body.innerText after settle.
|
|
114
|
-
```
|
|
110
|
+
Skip fetch. Write registry entry with `captured_via: delegated`, `delegated_to: pull-loop`. The actual workspace/page capture happens in `pull-loop` (see `plugin/skills/pull-loop/SKILL.md`), which uses the canonical Loop boundary in `<project>/integrations.yml#boundaries.loop.workspace_ids[]` rather than free-text `external-links.txt` URLs.
|
|
115
111
|
|
|
116
|
-
If
|
|
112
|
+
If the Loop URL pasted into `external-links.txt` references a workspace NOT registered in `boundaries.loop.workspace_ids[]`, `pull-misc` records `last_status: unregistered-loop-workspace` and notes the URL in `<project>/OPEN-QUESTIONS-DRAFT.md` so the user can decide whether to register it via `@Kushi setup --reconfigure`.
|
|
117
113
|
|
|
118
114
|
### B.2 `web` / `confluence` / `learn` / `docs` / `github` / unknown — HTTP
|
|
119
115
|
|
|
@@ -134,9 +130,9 @@ If login redirect detected: `last_status: auth-required`, `captured_via: browser
|
|
|
134
130
|
// Read text; if binary, mark last_status: skipped-binary (use a different pipeline if needed).
|
|
135
131
|
```
|
|
136
132
|
|
|
137
|
-
### B.4 `onenote` / `sharepoint` / `ado` — delegate
|
|
133
|
+
### B.4 `onenote` / `sharepoint` / `ado` / `loop` — delegate
|
|
138
134
|
|
|
139
|
-
Skip fetch. Write registry entry with `captured_via: delegated`, `delegated_to: pull-onenote|pull-sharepoint|pull-ado`. Per-skill captures already happen in their own pipelines.
|
|
135
|
+
Skip fetch. Write registry entry with `captured_via: delegated`, `delegated_to: pull-onenote|pull-sharepoint|pull-ado|pull-loop`. Per-skill captures already happen in their own pipelines.
|
|
140
136
|
|
|
141
137
|
## Per-link retry registry
|
|
142
138
|
|
|
@@ -151,7 +147,7 @@ Stored at `m365-mutable.json#knownSections.<projectKey>.misc_links[]`. Schema:
|
|
|
151
147
|
"notes": "<as in external-links.txt>",
|
|
152
148
|
"last_status": "captured | placeholder | auth-required | fetch-failed | skipped-binary | removed | not-yet-attempted | delegated",
|
|
153
149
|
"captured_via": "browser | http | file | delegated",
|
|
154
|
-
"delegated_to": "pull-onenote | pull-sharepoint | pull-ado", // only when captured_via=delegated
|
|
150
|
+
"delegated_to": "pull-onenote | pull-sharepoint | pull-ado | pull-loop", // only when captured_via=delegated
|
|
155
151
|
"http_status": 200, // only for HTTP
|
|
156
152
|
"content_type": "text/html", // only for HTTP
|
|
157
153
|
"char_count": 12345,
|
|
@@ -255,3 +251,13 @@ Citations from misc evidence MUST follow:
|
|
|
255
251
|
```
|
|
256
252
|
|
|
257
253
|
Example: `[source: misc/loop/ABN-Core-Team-Sync-2026-03-27 · 2026-05-14]`
|
|
254
|
+
|
|
255
|
+
## References (v4.4.7)
|
|
256
|
+
|
|
257
|
+
- Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
|
|
258
|
+
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
## Issue Recovery
|
|
262
|
+
|
|
263
|
+
When this skill exposes a reusable defect (auth pattern, doctrine gap, layout mismatch), apply the [Issue Recovery Rule](../../instructions/issue-recovery.instructions.md): fix the smallest correct repo-owned artifact first, prefer durable fixes over per-run workarounds, then re-run the narrowest failed check. Do NOT use memory as a substitute for correcting the workflow surface.
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "pull-onenote"
|
|
3
|
-
version: "2.
|
|
4
|
-
description: "Pull OneNote evidence (snapshot: full page bodies; stream: page-edit events).
|
|
3
|
+
version: "2.7.0"
|
|
4
|
+
description: "Pull OneNote evidence (snapshot: full page bodies; stream: page-edit events). WorkIQ natural-language queries by display name are the PRIMARY capture path (per workiq-onenote-query-shape.instructions.md). Playwright browser-scrape is OPT-IN, RECOVERY-ONLY fallback — never invoked unless the user has set m365Auth.oneNote.playwrightFallback: true AND the per-page retry registry shows persistent BODY-NOT-EXPOSED across multiple refreshes. Per-page retry registry persists both ID forms (browser webPageId + WorkIQ wdpartid) when both are observed; wdpartid alone is sufficient for WorkIQ-only operation."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Skill: pull-onenote
|
|
8
8
|
|
|
9
|
-
> **v3.8.0
|
|
9
|
+
> **v2.7.0 contract change (kushi v4.7.3, 2026-05-26):** Playwright is **demoted from PRIMARY to opt-in recovery-only fallback**. WorkIQ natural-language queries by display name are now the primary path. See `..\..\instructions\workiq-onenote-query-shape.instructions.md` for the working query shapes and the empirical record. The v3.8.0 pivot to Playwright-primary was driven by HCA body-retrieval rate (1/18 on 2026-05-14) — but per-page retry registries + multi-refresh accumulation close that gap without forcing every contributor onto Edge + Conditional Access + bootstrap-profile complexity.
|
|
10
|
+
|
|
11
|
+
> **v2.7.0 contracts** — This skill operates under seven HARD-rule doctrines:
|
|
12
|
+
> - `workiq-onenote-query-shape.instructions.md` — **PRIMARY**. The only working WorkIQ phrasings for OneNote.
|
|
10
13
|
> - `verbatim-by-default.instructions.md` — full bodies by default; no preview-grade pulls accepted.
|
|
11
|
-
> - `m365-id-registry.instructions.md` — discover-once / consume-deterministically (section IDs, dual page-id schema).
|
|
14
|
+
> - `m365-id-registry.instructions.md` — discover-once / consume-deterministically (section IDs, dual page-id schema when both observed).
|
|
12
15
|
> - `capture-learnings.instructions.md` — every fix/discovery is logged to `plugin/learnings/<source>.md`.
|
|
13
16
|
> - `cleanup-on-resolution.instructions.md` — when a value resolves, all stale unavailable-markers are upgraded in the same turn.
|
|
14
17
|
> - `run-reports.instructions.md` — every refresh writes a per-user report under `Evidence/<alias>/refresh-reports/`.
|
|
15
|
-
> - `thoroughness
|
|
18
|
+
> - `evidence-thoroughness.instructions.md` — runtime detector + auto-retry + paste-prompt for any page where the primary path returns nothing or partial. The per-page retry registry IS this skill's thoroughness contract.
|
|
16
19
|
|
|
17
20
|
> **Canonical evidence layout** (HARD, kushi v3.12.1+): all artifacts produced by this skill MUST be written under `<project>/Evidence/<alias>/<source>/{snapshot,stream,...}/` — sibling folders under `<project>/` (e.g. `<project>/<source>-context/`, `<project>/<source>/`, `<project>/_Weekly Summaries/`) are FORBIDDEN. See `evidence-layout-canonical.instructions.md`.
|
|
18
21
|
|
|
@@ -23,18 +26,56 @@ Pulls **onenote** evidence in two shapes per `snapshot-vs-stream.instructions.md
|
|
|
23
26
|
|
|
24
27
|
## Tools (in order)
|
|
25
28
|
|
|
26
|
-
1. **
|
|
27
|
-
2. **
|
|
28
|
-
3. **Host (m365_*)** — not used (Graph `Notes.Read.All` denied admin consent in this tenant).
|
|
29
|
+
1. **WorkIQ (natural-language by display name)** — **PRIMARY**. Use the approved query shapes from `workiq-onenote-query-shape.instructions.md`: one section per query, display names only, no enumeration verbs, no filter-syntax, no ID-lookup questions. Drives both section/page discovery and body retrieval. Pages that return `BODY-NOT-EXPOSED` are logged into `one_pages[].last_status` for retry on the next refresh — this multi-refresh accumulation is the thoroughness mechanism.
|
|
30
|
+
2. **Playwright (browser-scrape, persisted profile)** — **OPT-IN RECOVERY-ONLY FALLBACK**. Only invoked when ALL of: (a) `m365Auth.oneNote.playwrightFallback: true`, (b) `one_pages[]` shows ≥ N pages with `last_status: BODY-NOT-EXPOSED` for ≥ 2 consecutive refreshes (N default 5, configurable via `m365-mutable.json#pullOnenote.playwrightThreshold`), (c) WorkIQ has been attempted in the current run. Profile lives at `~/.kushi/playwright-profile/onenote/`. Implementation: `plugin/skills/pull-onenote/runner.mjs`. See "Playwright fallback (optional)" section below.
|
|
31
|
+
3. **Host (m365_*)** — not used (Graph `Notes.Read.All` denied admin consent in this tenant; also forbidden by kushi's WorkIQ-first doctrine).
|
|
29
32
|
|
|
30
|
-
## Canonical CLI invocations
|
|
33
|
+
## Canonical CLI invocations
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
### Primary path: WorkIQ natural-language (kushi v4.7.3+, default for all installs)
|
|
33
36
|
|
|
34
|
-
|
|
37
|
+
Per `..\..\instructions\workiq-onenote-query-shape.instructions.md`. Resolves section IDs and pulls page bodies via display-name queries:
|
|
35
38
|
|
|
36
39
|
```pwsh
|
|
37
|
-
|
|
40
|
+
# Per-section discovery + page enumeration (also extracts wdpartid + wdsectionfileid from URL fragments):
|
|
41
|
+
workiq ask -q "In the OneNote notebook '<NOTEBOOK DISPLAY NAME>', show me the pages in the section named '<SECTION DISPLAY NAME>'. Return a flat table with: page title, last modified, web URL. No commentary. Do not truncate."
|
|
42
|
+
|
|
43
|
+
# Per-page body pull (one page at a time — narrow scope is mandatory):
|
|
44
|
+
workiq ask -q "Open the OneNote page titled '<PAGE TITLE>' in section '<SECTION>' of notebook '<NOTEBOOK>'. Return the verbatim page body, no summary, no truncation."
|
|
45
|
+
|
|
46
|
+
# Edit-event stream:
|
|
47
|
+
workiq ask -q "Show me OneNote page edits in section '<SECTION>' of notebook '<NOTEBOOK>' since <ISO-DATE>. For each edit: page title, edited by, edited at, brief change summary."
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Driver behavior:
|
|
51
|
+
1. Run discovery query → parse `wdsectionfileid`, `wdpartid`, `sourcedoc` GUIDs out of the URL fragments in the response.
|
|
52
|
+
2. Persist into `m365-mutable.json#knownSections.<projectKey>` per `m365-id-registry.instructions.md`. `webPageId` is left empty — it is only populated if/when Playwright fallback runs.
|
|
53
|
+
3. For each enumerated page, run the body-pull query. Write snapshot files to the canonical layout. Populate `one_pages[].last_status`: `captured` on verbatim body return, `BODY-NOT-EXPOSED` on empty/partial, `workiq-degraded` on classified WorkIQ failure (per `fallback-status-reporting.instructions.md`).
|
|
54
|
+
4. Pages with `BODY-NOT-EXPOSED` are surfaced in the run report and queued for retry on the next refresh. The per-page retry registry is the thoroughness mechanism — over multiple refreshes, transient non-determinism is absorbed.
|
|
55
|
+
|
|
56
|
+
### Playwright fallback (OPT-IN, RECOVERY-ONLY — kushi v4.7.3+)
|
|
57
|
+
|
|
58
|
+
**Do NOT bootstrap a Playwright profile on a fresh install.** This path exists only as a recovery valve for contributors whose WorkIQ body-retrieval rate stays poor across multiple refreshes. Enable explicitly:
|
|
59
|
+
|
|
60
|
+
```jsonc
|
|
61
|
+
// In <kushi-config-root>/user/m365-auth.json:
|
|
62
|
+
"oneNote": {
|
|
63
|
+
"enabled": true,
|
|
64
|
+
"defaultNotebookName": "...",
|
|
65
|
+
"playwrightFallback": true // OPT-IN — default false
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Once opted in, the driver auto-escalates to Playwright when `one_pages[]` shows ≥ N pages with `last_status: BODY-NOT-EXPOSED` for ≥ 2 consecutive refreshes (N default 5; configurable via `m365-mutable.json#pullOnenote.playwrightThreshold`). Until both thresholds are met, the driver MUST continue using WorkIQ. Never auto-bootstrap a profile — that is always a user-initiated action.
|
|
70
|
+
|
|
71
|
+
The Playwright invocations below remain valid (cookie surfaces, channel requirements, preflight three-way classification are all empirically unchanged) — they are simply the **fallback** path now, not the default.
|
|
72
|
+
|
|
73
|
+
These are the empirically validated invocations as of kushi v3.11.3 (still in force for the fallback path). The runner has surprising defaults (visible browser by default, 60s timeout, preflight required) that can derail a run. Use these recipes; do not improvise flags.
|
|
74
|
+
|
|
75
|
+
### Bootstrap the Playwright profile (FALLBACK PATH ONLY — opt-in required)
|
|
76
|
+
|
|
77
|
+
```pwsh
|
|
78
|
+
cd <kushi-repo-root>
|
|
38
79
|
node plugin/skills/pull-onenote/runner.mjs --bootstrap
|
|
39
80
|
```
|
|
40
81
|
|
|
@@ -60,13 +101,13 @@ The bare `runner.mjs` emits JSON to stdout only. The driver (PowerShell or agent
|
|
|
60
101
|
**HARD rule (kushi v3.11.5+):** drivers MUST call `write-snapshot.mjs`, which invokes the runner internally (child_process, no shell pipe), writes the snapshot in the canonical layout, upserts `m365Mutable.knownSections.<project>.one_pages[]`, and emits a run report. Never hand-write snapshot files from runner JSON.
|
|
61
102
|
|
|
62
103
|
```pwsh
|
|
63
|
-
cd
|
|
104
|
+
cd <kushi-repo-root>
|
|
64
105
|
$url = '<exact-section-url-from-m365-mutable.json#one_sectionWebUrl>'
|
|
65
106
|
node plugin/skills/pull-onenote/write-snapshot.mjs `
|
|
66
107
|
--section-url $url `
|
|
67
108
|
--project "<project>" `
|
|
68
109
|
--engagement-root "<engagement-root>" `
|
|
69
|
-
--alias
|
|
110
|
+
--alias <your-alias>
|
|
70
111
|
```
|
|
71
112
|
|
|
72
113
|
Output structure (per `snapshot-vs-stream.instructions.md`):
|
|
@@ -130,13 +171,14 @@ await ctx.close();
|
|
|
130
171
|
|
|
131
172
|
Run: `node plugin/skills/pull-onenote/diag.mjs "<section-url>"`. If you see `, Page. Selected.` but not `, page N of M, Page.` → single-page section, runner must be v3.11.3+.
|
|
132
173
|
|
|
133
|
-
## Empirical contract (what is true, validated 2026-05-13/14)
|
|
174
|
+
## Empirical contract (what is true, validated 2026-05-13/14 + reframed 2026-05-26)
|
|
134
175
|
|
|
135
|
-
These
|
|
176
|
+
These facts are HARD-rule and supersede any earlier doctrine in this skill or in older learnings:
|
|
136
177
|
|
|
137
|
-
1. **
|
|
138
|
-
2. **WorkIQ is non-deterministic
|
|
139
|
-
3. **The OneNote-for-Web `pageid` and the WorkIQ `wdpartid` are different identifiers.** Both
|
|
178
|
+
1. **WorkIQ natural-language by display name IS the primary, working path for OneNote.** Reframed v4.7.3 (2026-05-26) — see `..\..\instructions\workiq-onenote-query-shape.instructions.md`. The only WorkIQ phrasings that work are: (a) narrow, single-section-by-display-name discovery queries; (b) single-page-by-title body pulls; (c) section-scoped edit-event stream queries. Forbidden: enumeration verbs, structured-field filter syntax, ID-lookup questions, broad "list my notebooks" probes. Those all empirically fail (WorkIQ punts to Graph Explorer or routes to summary mode).
|
|
179
|
+
2. **WorkIQ body retrieval is non-deterministic, BUT per-page retry registries close the gap over multiple refreshes.** The v3.8.0 pivot to Playwright was driven by HCA's 1-of-18 body-retrieval rate on 2026-05-14. That rate is the snapshot of one refresh — the retry registry (`one_pages[].last_status`) is the durable mechanism that accumulates captures across refreshes. A page that returns `BODY-NOT-EXPOSED` today is retried tomorrow; over 3-5 refreshes the cumulative capture rate converges. This is acceptable for engagement evidence (which is time-windowed, not real-time). Playwright remains as the opt-in recovery valve for contributors who need faster convergence and have accepted the Edge + Conditional Access + bootstrap complexity.
|
|
180
|
+
3. **The OneNote-for-Web `pageid` and the WorkIQ `wdpartid` are different identifiers.** Both should be persisted per page when both are observed (`webPageId` for browser navigation; `wdpartid` for WorkIQ correlation and stream events). For WorkIQ-only operation, `wdpartid` alone is sufficient — `webPageId` is only populated if/when Playwright fallback runs.
|
|
181
|
+
4. **Browser-scrape via OneNote-for-Web returns higher-fidelity verbatim bodies when it works** — tested against HCA on 2026-05-14: 16 of 16 pages captured (~120KB) in one run. This is why Playwright remains as the opt-in fallback. It is NOT the default because: (a) it requires Edge + Conditional Access compliance — not all contributors have that; (b) it requires a per-machine bootstrap that expires every 3-5 days; (c) most engagements do not need real-time full-fidelity capture — multi-refresh WorkIQ converges adequately.
|
|
140
182
|
|
|
141
183
|
## Pre-flight
|
|
142
184
|
|
|
@@ -429,3 +471,13 @@ Every refresh writes `Evidence/<alias>/refresh-reports/<YYYY-MM-DD>-<HHMM>-oneno
|
|
|
429
471
|
- Any short-suspect entries needing user verification
|
|
430
472
|
|
|
431
473
|
|
|
474
|
+
|
|
475
|
+
## References (v4.4.7)
|
|
476
|
+
|
|
477
|
+
- Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
|
|
478
|
+
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
## Issue Recovery
|
|
482
|
+
|
|
483
|
+
When this skill exposes a reusable defect (auth pattern, doctrine gap, layout mismatch), apply the [Issue Recovery Rule](../../instructions/issue-recovery.instructions.md): fix the smallest correct repo-owned artifact first, prefer durable fixes over per-run workarounds, then re-run the narrowest failed check. Do NOT use memory as a substitute for correcting the workflow surface.
|
|
@@ -21,7 +21,7 @@ Pulls **sharepoint** evidence in two shapes per `snapshot-vs-stream.instructions
|
|
|
21
21
|
- **snapshot/** — tree.md (full folder tree) + files/<path>.md (key files with full extracted content)
|
|
22
22
|
- **stream/** — file change events (created/modified/renamed/deleted) with author + size + brief content summary
|
|
23
23
|
|
|
24
|
-
Thoroughness per `evidence-thoroughness.instructions.md`; runtime detector + auto-retry + paste-prompt per `thoroughness
|
|
24
|
+
Thoroughness per `evidence-thoroughness.instructions.md`; runtime detector + auto-retry + paste-prompt per `evidence-thoroughness.instructions.md`. Citations per `citation-ledger.instructions.md`. Side-by-side mutable hints written immediately on discovery per `side-by-side-config.instructions.md`.
|
|
25
25
|
|
|
26
26
|
## Inputs
|
|
27
27
|
|
|
@@ -114,4 +114,13 @@ Every snapshot file body starts with an **AI Narrative Summary (REQUIRED FIRST,
|
|
|
114
114
|
|
|
115
115
|
- Hint missing AND fuzzy resolution returns 0 candidates → ask user once, persist answer to mutable, continue.
|
|
116
116
|
- Multiple plausible candidates → ask user to pick, persist answer.
|
|
117
|
-
- WorkIQ fails (after doubled-strict retry) AND user declines to paste → write evidence file with `❌ workiq-empty-after-retry` marker, log to run-log errors with `next_step: re-run after WorkIQ recovery or paste verbatim`, continue with rest of run. Do NOT fall through to Graph / `m365_*` — FORBIDDEN per workiq-only.
|
|
117
|
+
- WorkIQ fails (after doubled-strict retry) AND user declines to paste → write evidence file with `❌ workiq-empty-after-retry` marker, log to run-log errors with `next_step: re-run after WorkIQ recovery or paste verbatim`, continue with rest of run. Do NOT fall through to Graph / `m365_*` — FORBIDDEN per workiq-only.
|
|
118
|
+
## References (v4.4.7)
|
|
119
|
+
|
|
120
|
+
- Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
|
|
121
|
+
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
## Issue Recovery
|
|
125
|
+
|
|
126
|
+
When this skill exposes a reusable defect (auth pattern, doctrine gap, layout mismatch), apply the [Issue Recovery Rule](../../instructions/issue-recovery.instructions.md): fix the smallest correct repo-owned artifact first, prefer durable fixes over per-run workarounds, then re-run the narrowest failed check. Do NOT use memory as a substitute for correcting the workflow surface.
|
|
@@ -21,7 +21,7 @@ Pulls **teams** evidence in two shapes per `snapshot-vs-stream.instructions.md`:
|
|
|
21
21
|
- **snapshot/** — chat roster + member list per chat the user is part of for this project
|
|
22
22
|
- **stream/** — messages with full message-by-message reproduction — sender, timestamp, verbatim text, reactions, attachments, replies — grouped by thread
|
|
23
23
|
|
|
24
|
-
Thoroughness per `evidence-thoroughness.instructions.md`; runtime detector + auto-retry + paste-prompt per `thoroughness
|
|
24
|
+
Thoroughness per `evidence-thoroughness.instructions.md`; runtime detector + auto-retry + paste-prompt per `evidence-thoroughness.instructions.md`. Citations per `citation-ledger.instructions.md`. Side-by-side mutable hints written immediately on discovery per `side-by-side-config.instructions.md`.
|
|
25
25
|
|
|
26
26
|
## Inputs
|
|
27
27
|
|
|
@@ -101,4 +101,13 @@ After successful pass:
|
|
|
101
101
|
|
|
102
102
|
- Hint missing AND fuzzy resolution returns 0 candidates → ask user once, persist answer to mutable, continue.
|
|
103
103
|
- Multiple plausible candidates → ask user to pick, persist answer.
|
|
104
|
-
- WorkIQ fails (after doubled-strict retry) AND user declines to paste → write evidence file with `❌ workiq-empty-after-retry` marker, log to run-log errors with `next_step: re-run after WorkIQ recovery or paste verbatim`, continue with rest of run. Do NOT fall through to Graph / `m365_*` — FORBIDDEN per workiq-only.
|
|
104
|
+
- WorkIQ fails (after doubled-strict retry) AND user declines to paste → write evidence file with `❌ workiq-empty-after-retry` marker, log to run-log errors with `next_step: re-run after WorkIQ recovery or paste verbatim`, continue with rest of run. Do NOT fall through to Graph / `m365_*` — FORBIDDEN per workiq-only.
|
|
105
|
+
## References (v4.4.7)
|
|
106
|
+
|
|
107
|
+
- Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
|
|
108
|
+
- After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
## Issue Recovery
|
|
112
|
+
|
|
113
|
+
When this skill exposes a reusable defect (auth pattern, doctrine gap, layout mismatch), apply the [Issue Recovery Rule](../../instructions/issue-recovery.instructions.md): fix the smallest correct repo-owned artifact first, prefer durable fixes over per-run workarounds, then re-run the narrowest failed check. Do NOT use memory as a substitute for correcting the workflow surface.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "refresh-project"
|
|
3
|
-
version: "2.3.
|
|
3
|
+
version: "2.3.2"
|
|
4
4
|
description: "Incremental refresh for an already-bootstrapped project. Reads run-log watermarks, pulls only what is new since last run per source, splits stream output by ISO week, replaces snapshots in place. Verbatim-by-default per `verbatim-by-default.instructions.md` — every enabled source MUST be dispatched, no silent skips. Writes per-user refresh report per `run-reports.instructions.md`. Cleans stale no-match notes on resolution per `cleanup-on-resolution.instructions.md`. Builds State/ only on `full` profile."
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -43,6 +43,7 @@ Profile is read from `kushi-install.json#profile` next to the agent file. Defaul
|
|
|
43
43
|
|
|
44
44
|
### Step 1 — Resolve project + read run-log
|
|
45
45
|
|
|
46
|
+
- **Sync-pending gate (v4.5.0):** before resolving, check `<workspace>/.kushi/config/user/project-evidence.yml#projects_root_status`. If `syncing` or `manual-sync-pending`, refuse: *"Engagement root sync still pending. Run `@Kushi setup --resume-sync` once OneDrive finishes."* Exit cleanly.
|
|
46
47
|
- Fuzzy-match `<project>` per `engagement-root-resolution.instructions.md`.
|
|
47
48
|
- Read `<engagement-root>/<project>/Evidence/run-log.yml`.
|
|
48
49
|
- For each source, compute effective window:
|
|
@@ -86,10 +87,11 @@ Per-source pull skills (canonical order — refresh-project dispatches in this o
|
|
|
86
87
|
2. `pull-teams`
|
|
87
88
|
3. `pull-meetings`
|
|
88
89
|
4. `pull-onenote`
|
|
89
|
-
5. `pull-
|
|
90
|
-
6. `pull-
|
|
91
|
-
7. `pull-
|
|
92
|
-
8. `pull-
|
|
90
|
+
5. `pull-loop` (if enabled — boundary `boundaries.loop.workspace_ids[]` populated)
|
|
91
|
+
6. `pull-sharepoint`
|
|
92
|
+
7. `pull-crm` (if enabled)
|
|
93
|
+
8. `pull-ado` (if enabled)
|
|
94
|
+
9. `pull-misc` (if `<project>/external-links.txt` exists)
|
|
93
95
|
|
|
94
96
|
Each `pull-*` skill is responsible for:
|
|
95
97
|
- Snapshot pass (always re-fetch known entities).
|
|
@@ -97,6 +99,25 @@ Each `pull-*` skill is responsible for:
|
|
|
97
99
|
- Updating `sources.<src>.watermark`, `sources.<src>.last_pulled`, `sources.<src>.item_count` in run-log.
|
|
98
100
|
- Updating `weekly_files` index in run-log.
|
|
99
101
|
|
|
102
|
+
**Verification gate after each per-source dispatch (v4.4.8+, HARD):** Per `..\..\instructions\per-source-verification-gate.instructions.md`, immediately after each `pull-*` returns:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
gate = run_verification_gate(source, result)
|
|
106
|
+
if gate.status == "fail":
|
|
107
|
+
retry = dispatch(source, --window <same>, --retry)
|
|
108
|
+
gate2 = run_verification_gate(source, retry)
|
|
109
|
+
if gate2.status == "fail":
|
|
110
|
+
append_to_followups(<project>/FOLLOW-UPS.md, gate2) # 5-field shape (D19)
|
|
111
|
+
append_to_runlog(<project>/Evidence/run-log.yml,
|
|
112
|
+
source, status: "failed-gate",
|
|
113
|
+
gate_failures: gate2.failures,
|
|
114
|
+
process_audit: gate2.process_audit_failures)
|
|
115
|
+
append_to_tracking(gate2.process_audit_failures)
|
|
116
|
+
# do NOT abort the whole refresh — continue to next source
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Refresh is **never** aborted by a single source's gate failure. The gate's job is to surface — not to block.
|
|
120
|
+
|
|
100
121
|
**pull-misc dispatch:** invoke as `node plugin/skills/pull-misc/runner.mjs --project <name> --links-file <engagement-root>/<project>/external-links.txt --engagement-root <engagement-root> --headless`. Parse the JSON output, write per-link snapshot files to `Evidence/<alias>/misc/snapshot/<safe-type>__<safe-title>.md`, and merge the `links[]` records into `m365-mutable.json#knownSections.<projectKey>.misc_links[]` (preserving prior `attempts`, bumping `last_attempt_at`).
|
|
101
122
|
|
|
102
123
|
### Step 3 — Consolidate (if multi-user)
|
|
@@ -112,9 +133,10 @@ If `standard` (or `core`) → **skip this step**. Note in the run summary: *"Sta
|
|
|
112
133
|
### Step 5 — Run summary
|
|
113
134
|
|
|
114
135
|
Display:
|
|
115
|
-
- Per-source table: items pulled, weeks affected, errors.
|
|
136
|
+
- Per-source table: items pulled, weeks affected, errors, **gate status** (pass / retried-pass / failed-followups-written).
|
|
116
137
|
- Side-by-side mutable hints written this run (per `side-by-side-config.instructions.md`).
|
|
117
138
|
- New Open Questions opened/resolved/staled.
|
|
139
|
+
- **Open follow-ups delta** — count of entries newly written to `<project>/FOLLOW-UPS.md` this run + count of entries auto-moved from Open → Resolved by `cleanup-on-resolution.instructions.md`.
|
|
118
140
|
|
|
119
141
|
## Watermark semantics
|
|
120
142
|
|
|
@@ -137,4 +159,13 @@ Re-running refresh with the same window is safe:
|
|
|
137
159
|
- "update `<X>`"
|
|
138
160
|
- "pull `<X>` since `<date>`"
|
|
139
161
|
- "refresh `<X>` last `<N>` days"
|
|
140
|
-
- "backfill `<X>` from `<from>` to `<to>`"
|
|
162
|
+
- "backfill `<X>` from `<from>` to `<to>`"
|
|
163
|
+
## References (v4.4.7)
|
|
164
|
+
|
|
165
|
+
- Name → ID resolution (any source) follows `..\..\instructions\fuzzy-disambiguation.instructions.md`.
|
|
166
|
+
- After each per-source pull, run the gate per `..\..\instructions\per-source-verification-gate.instructions.md` (retry once → FOLLOW-UPS.md on failure).
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
## Issue Recovery
|
|
170
|
+
|
|
171
|
+
When this skill exposes a reusable defect (auth pattern, doctrine gap, layout mismatch), apply the [Issue Recovery Rule](../../instructions/issue-recovery.instructions.md): fix the smallest correct repo-owned artifact first, prefer durable fixes over per-run workarounds, then re-run the narrowest failed check. Do NOT use memory as a substitute for correcting the workflow surface.
|
|
@@ -46,7 +46,20 @@ Checks split into **core** (always run) and **deep** (opt-in).
|
|
|
46
46
|
| D4 | Live install sync | if `~/.copilot/m-skills/kushi/` exists, its `SKILL.md` is byte-identical to `plugin/agents/kushi.agent.md` |
|
|
47
47
|
| D5 | skills-metadata.json sync | if `~/.copilot/m-skills/skills-metadata.json` lists `kushi`, its description matches the live `SKILL.md` frontmatter |
|
|
48
48
|
| D6 | Side-by-side rule cited | every SKILL.md that touches user config references `side-by-side-config.instructions.md` |
|
|
49
|
-
|
|
|
49
|
+
| D15 | Legacy path regression | no `.project-evidence/{m365,crm,ado}` references outside CHANGELOG / learnings (v4.4.0+ moved per-user config to `<workspace>/.kushi/config/{user,shared}/`) |
|
|
50
|
+
| D16 | Cross-platform parity | every contributor-facing install/setup surface (setup/SKILL.md, install-workiq.md, check-workiq.mjs) addresses BOTH Windows (`winget` + `win32` branch) and macOS (`brew` + `darwin` branch). Also: self-check ships both `run.ps1` and `run.sh`. |
|
|
51
|
+
| D17 | Fuzzy disambiguation cited | every name→ID resolver (pull-onenote / pull-sharepoint / pull-teams / pull-crm / pull-ado / pull-email / ask-project / engagement-root-resolution) cites `fuzzy-disambiguation.instructions.md`. |
|
|
52
|
+
| D18 | Verification gate cited | every pull-* skill + bootstrap-project + refresh-project + aggregate-project cites `per-source-verification-gate.instructions.md`. |
|
|
53
|
+
| D19 | FOLLOW-UPS format | when `<project>/FOLLOW-UPS.md` exists, every `## Open follow-ups` entry has the 5 required fields (Gate failures / Next-time-do / Tracking / Run-log entry / Status). |
|
|
54
|
+
| D20 | README verbs coverage | every `plugin/prompts/<verb>.prompt.md` has a row in README's `## Verbs` table, and every row maps to a real prompt (or known alias). |
|
|
55
|
+
| D21 | Cross-platform .ps1 scripts | every `.ps1` in the repo runs on pwsh 7 cross-platform — Windows-only APIs (`Get-WmiObject`, `Win32_*`, COM, `HKLM:`) are gated with `if ($IsWindows)`. |
|
|
56
|
+
| D22 | Duplicate / overlap detection | flag pairs of `plugin/instructions/*.instructions.md` whose `description:` frontmatter has ≥ 60% word overlap — these are candidates for merge or scope-clarification. |
|
|
57
|
+
| D23 | Instructions map parity | every `plugin/instructions/*.instructions.md` is listed in `docs/reference/instructions-map.md`; every row in the map maps to a real file. |
|
|
58
|
+
| D24 | OneDrive pin policy applicable | when `projects_root` is INSIDE a OneDrive-managed path AND OneDrive is running, warn if own-alias `Evidence/<my-alias>/` exists but appears cloud-only (Windows: `attrib` shows `+U`; macOS: `xattr` lacks `com.microsoft.OneDrive.PinnedToDevice`). Surface as "may slow writes; re-run @Kushi setup --reconfigure to re-pin". Cited from `onedrive-pin-policy.instructions.md`. |
|
|
59
|
+
| D25 | Documentation coverage | every `plugin/instructions/*.instructions.md` is mentioned in EITHER `docs/reference/instructions-map.md` (mandatory via D23) AND at least one of: `CHANGELOG.md`, a `docs/concepts/*.md` doc, a `docs/reference/*.md` doc, or a `docs/how-to/*.md` doc. Catches new doctrines that landed without any user-facing prose. |
|
|
60
|
+
| D26 | Issue Recovery cite | every skill in the recovery-required set (`pull-*`, `aggregate-project`, `consolidate-evidence`, `bootstrap-project`, `refresh-project`, `apply-ado-update`, `propose-ado-update`) cites `issue-recovery.instructions.md` in its References section. Ensures the Issue Recovery Rule applies whenever an external service exposes a doctrine gap. |
|
|
61
|
+
| D27 | Personal-path leakage | no contributor-specific path / email / repo-local-path patterns (`OneDrive - Microsoft\ISE\Engagement Assets`, `C:\Users\<contributor>`, `<contributor>@microsoft.com`, etc.) appear in `plugin/`, `docs/getting-started/`, or `README.md`. Examples must use placeholders. Exemptions: `CHANGELOG.md`, `plugin/learnings/`, `plugin/reference-packs/`. |
|
|
62
|
+
| D28 | Predecessor-agent leakage | no current-doc file in `plugin/` or `docs/` references the historical predecessor agent by name. Use neutral language ('predecessor agent' / 'another internal agent'). Exemptions: `CHANGELOG.md` (historical commit notes), `plugin/learnings/`, `plugin/reference-packs/`, `docs/reference/instructions-map.md`. |
|
|
50
63
|
|
|
51
64
|
## Execution flow (agent path)
|
|
52
65
|
|