kushi-agents 3.4.2 → 3.12.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/README.md +33 -0
- package/package.json +15 -3
- package/plugin/agents/kushi.agent.md +155 -147
- package/plugin/instructions/ado-bootstrap-discovery.instructions.md +111 -0
- package/plugin/instructions/ado-engagement-tree.instructions.md +73 -0
- package/plugin/instructions/answer-from-evidence.instructions.md +1 -1
- package/plugin/instructions/auth-and-retry.instructions.md +51 -16
- package/plugin/instructions/azure-auth-patterns.instructions.md +13 -6
- package/plugin/instructions/bootstrap-status-format.instructions.md +113 -0
- package/plugin/instructions/capture-learnings.instructions.md +95 -0
- package/plugin/instructions/cleanup-on-resolution.instructions.md +69 -0
- package/plugin/instructions/crm-bootstrap-discovery.instructions.md +79 -0
- package/plugin/instructions/crm-internal-vs-confirmed.instructions.md +79 -0
- package/plugin/instructions/evidence-confidence-ladder.instructions.md +66 -0
- package/plugin/instructions/evidence-layout-canonical.instructions.md +115 -0
- package/plugin/instructions/evidence-thoroughness.instructions.md +82 -12
- package/plugin/instructions/full-view-gate.instructions.md +91 -0
- package/plugin/instructions/m365-id-registry.instructions.md +134 -0
- package/plugin/instructions/meetings-verbatim-required.instructions.md +176 -0
- package/plugin/instructions/run-reports.instructions.md +129 -0
- package/plugin/instructions/scope-boundaries.instructions.md +218 -0
- package/plugin/instructions/snapshot-vs-stream.instructions.md +2 -0
- package/plugin/instructions/update-ledger.instructions.md +132 -0
- package/plugin/instructions/verbatim-by-default.instructions.md +73 -0
- package/plugin/instructions/workiq-first.instructions.md +15 -31
- package/plugin/instructions/workiq-only.instructions.md +193 -0
- package/plugin/learnings/README.md +50 -0
- package/plugin/learnings/ado.md +45 -0
- package/plugin/learnings/crm.md +96 -0
- package/plugin/learnings/cross-cutting.md +36 -0
- package/plugin/learnings/email.md +33 -0
- package/plugin/learnings/meetings.md +30 -0
- package/plugin/learnings/misc.md +46 -0
- package/plugin/learnings/onenote.md +215 -0
- package/plugin/learnings/sharepoint.md +5 -0
- package/plugin/learnings/teams.md +5 -0
- package/plugin/plugin.json +22 -2
- package/plugin/prompts/apply-ado.prompt.md +14 -0
- package/plugin/prompts/propose-ado.prompt.md +12 -0
- package/plugin/reference-packs/fde/crm-field-manifest.md +165 -0
- package/plugin/skills/apply-ado-update/SKILL.md +125 -0
- package/plugin/skills/ask-project/SKILL.md +2 -0
- package/plugin/skills/bootstrap-project/SKILL.md +81 -3
- package/plugin/skills/propose-ado-update/SKILL.md +108 -0
- package/plugin/skills/pull-ado/SKILL.md +173 -23
- package/plugin/skills/pull-crm/SKILL.md +168 -15
- package/plugin/skills/pull-email/SKILL.md +139 -22
- package/plugin/skills/pull-meetings/SKILL.md +109 -25
- package/plugin/skills/pull-misc/README.md +84 -0
- package/plugin/skills/pull-misc/SKILL.md +257 -0
- package/plugin/skills/pull-misc/runner.mjs +280 -0
- package/plugin/skills/pull-onenote/README.md +90 -0
- package/plugin/skills/pull-onenote/SKILL.md +400 -51
- package/plugin/skills/pull-onenote/runner.mjs +356 -0
- package/plugin/skills/pull-onenote/scripts/recapture-section-url.mjs +295 -0
- package/plugin/skills/pull-onenote/write-snapshot.mjs +271 -0
- package/plugin/skills/pull-sharepoint/SKILL.md +44 -12
- package/plugin/skills/pull-teams/SKILL.md +40 -11
- package/plugin/skills/refresh-project/SKILL.md +33 -2
- package/plugin/skills/self-check/run.ps1 +186 -4
- package/plugin/templates/ado-update/discussion-comment.template.md +26 -0
- package/plugin/templates/ado-update/integrations-ado-writes.example.yml +49 -0
- package/plugin/templates/ado-update/proposed.template.md +78 -0
- package/plugin/templates/init/external-links.template.txt +30 -0
- package/plugin/templates/init/project-integrations.template.yml +57 -2
- package/plugin/templates/snapshot/meeting-verbatim.template.md +110 -0
- package/plugin/templates/snapshot/meetings-series-index.template.md +3 -1
- package/plugin/templates/snapshot/onenote-page.template.md +92 -23
- package/plugin/templates/weekly/meetings-stream.template.md +11 -6
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "pull-email"
|
|
3
|
-
version: "2.
|
|
4
|
-
description: "Pull Email evidence (stream only — emails ARE events). WorkIQ-
|
|
3
|
+
version: "2.3.1"
|
|
4
|
+
description: "Pull Email evidence (stream only — emails ARE events). WorkIQ-ONLY per workiq-only.instructions.md (m365_get_email / m365_search_emails / Graph REST FORBIDDEN — near-100% failure in this workspace). Folder-scoped fast path → root-scope WorkIQ fallback. Enumerate-then-fetch via two WorkIQ calls per project. Mutable folder-hint upsert during run. Throttle-aware. User-paste is a first-class fallback, NOT Graph."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Skill: pull-email
|
|
8
8
|
|
|
9
|
+
|
|
10
|
+
> **v3.7.6 + v3.11.0 contracts** — This skill operates under five HARD-rule doctrines:
|
|
11
|
+
> - `verbatim-by-default.instructions.md` — full bodies/notetext/fields by default; no preview-grade pulls accepted.
|
|
12
|
+
> - **`workiq-only.instructions.md` (v3.11.0)** — email list + body fetch go through WorkIQ ONLY. `m365_get_email`, `m365_search_emails`, `m365_list_emails`, and Graph REST URLs are FORBIDDEN as fallbacks (they fail nearly every call in this workspace). The canonical WorkIQ prompts (folder-scoped enumerate, root-scope fallback, per-message body fetch) are codified in that instruction — do not re-discover them.
|
|
13
|
+
> - `capture-learnings.instructions.md` — every fix/discovery is logged to `plugin/learnings/<source>.md` immediately.
|
|
14
|
+
> - `cleanup-on-resolution.instructions.md` — when a value resolves, all stale `no-match` / `not yet` notes referencing the prior unresolved state must be rewritten in the same turn.
|
|
15
|
+
> - `run-reports.instructions.md` — every refresh writes a per-user report under `Evidence/<alias>/refresh-reports/YYYY-MM-DD-HHMM_refresh.md`.
|
|
16
|
+
> - `evidence-layout-canonical.instructions.md` (kushi v3.12.1+) — ALL email artifacts MUST be written under `<project>/Evidence/<alias>/email/{snapshot,stream,_index,_legacy_*}/`. Writing to `<project>/email-context/`, `<project>/email/`, `<project>/_Weekly Summaries/`, or any other sibling path under `<project>/` is a DEFECT.
|
|
9
17
|
Pulls **email** evidence in two shapes per `snapshot-vs-stream.instructions.md`:
|
|
10
18
|
|
|
11
19
|
- **snapshot/** — (none — emails ARE events, no snapshot)
|
|
12
20
|
- **stream/** — messages with full body, sender, recipients, attachments, reply chain — grouped by thread
|
|
13
21
|
|
|
14
|
-
|
|
22
|
+
Thoroughness per `evidence-thoroughness.instructions.md`; runtime detector + auto-retry + paste-prompt per `thoroughness-detector.instructions.md`. Citations per `citation-ledger.instructions.md`. Side-by-side mutable hints written immediately on discovery per `side-by-side-config.instructions.md`.
|
|
15
23
|
|
|
16
24
|
## Inputs
|
|
17
25
|
|
|
@@ -26,50 +34,159 @@ WorkIQ-first per `workiq-first.instructions.md`. Thoroughness per `evidence-thor
|
|
|
26
34
|
- `emailContext.folder` — full path of the project's email folder
|
|
27
35
|
- `emailContext.folderId` — folder ID for direct lookup
|
|
28
36
|
|
|
29
|
-
##
|
|
37
|
+
## Boundaries (REQUIRED — see `scope-boundaries.instructions.md`)
|
|
30
38
|
|
|
31
|
-
|
|
39
|
+
This skill REFUSES to query unless `<engagement-root>/<project>/integrations.yml#boundaries.email` is satisfied:
|
|
40
|
+
|
|
41
|
+
- `boundaries.email.mailboxes` — REQUIRED, non-empty. Empty = source disabled.
|
|
42
|
+
- `boundaries.email.sender_domains` — optional narrowing.
|
|
43
|
+
- `boundaries.email.subject_keywords` — optional narrowing.
|
|
44
|
+
- `boundaries.date_window_days` — defaults to 30 if absent.
|
|
45
|
+
|
|
46
|
+
Every WorkIQ ask, every `m365_search_emails` / `m365_list_emails` call, every Graph fallback MUST be scoped to those mailboxes + (if set) sender_domains + subject_keywords. Empty hits inside the boundary → write Coverage Notes citing the limiting key; do NOT widen the scope.
|
|
47
|
+
|
|
48
|
+
Refusal message when boundary is missing:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
email-boundary-missing — add boundaries.email.mailboxes to
|
|
52
|
+
<engagement-root>/<project>/integrations.yml. See doctrine in
|
|
53
|
+
plugin/instructions/scope-boundaries.instructions.md.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Retrieval order (deterministic — folder fast path → root fallback)
|
|
57
|
+
|
|
58
|
+
Borrowed from production email-context hardening. WorkIQ is more reliable when the query is folder-scoped to one known project folder than when it scans the whole mailbox. Order:
|
|
59
|
+
|
|
60
|
+
### Order 1 — Exact project-folder fast path (when hint exists)
|
|
61
|
+
|
|
62
|
+
If `m365Mutable.knownSections.<project>.emailContext.folder` (or `.folderId`) is set with `confidence >= medium`:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
workiq ask -q "Search my Outlook mailbox for emails from <window-start> onward in folder(s) '<projectFolder>' (including all subfolders) related to <project aliases>. Return: sent datetime, subject, sender, recipients, folder path, message link, and a short relevance reason. Do not return NO_RESULTS unless the folder truly has no messages in that range."
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
If this path returns 0 results AND the same query has succeeded recently in this project's run-log, retry the exact-folder query ONCE before escalating. WorkIQ has been observed to return spurious empty hits on first call.
|
|
69
|
+
|
|
70
|
+
### Order 2 — Root-scope fallback
|
|
71
|
+
|
|
72
|
+
Only if Order 1 returns insufficient/empty results after the retry, OR the project has no folder hint, OR multiple plausible hints exist:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
workiq ask -q "Search my Outlook mailbox for emails from <window-start> onward in folder(s) <boundaries.email.mailboxes joined> (including all subfolders) related to <project aliases>. Return: sent datetime, subject, sender, recipients, folder path, message link, and a short relevance reason."
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Throttle handling (HARD stop in same run)
|
|
79
|
+
|
|
80
|
+
If WorkIQ returns `tooManyRequests`, `More than 3 retries performed`, or `We're experiencing high demand`:
|
|
81
|
+
|
|
82
|
+
- Mark `sources.email.coverage_state = throttled-tooManyRequests` in run-log.
|
|
83
|
+
- Write what enumeration HAS been collected so far to the message-index file with a `⚠️ throttled — partial enumeration` banner.
|
|
84
|
+
- Stop email pulls for this run. Do NOT issue broader mailbox queries.
|
|
85
|
+
- Continue with non-email sources.
|
|
86
|
+
|
|
87
|
+
### Degraded list-only state
|
|
88
|
+
|
|
89
|
+
If Step A enumeration succeeds but Step B body fetch fails repeatedly (host + WorkIQ both returning empty / `body-unavailable` for >50% of messages):
|
|
90
|
+
|
|
91
|
+
- Set `sources.email.coverage_state = degraded-list-only`.
|
|
92
|
+
- Keep the message index with sent date, subject, sender, recipients, folder path, message link as evidence — these ARE usable signals at list level.
|
|
93
|
+
- Mark each affected message with `❌ body-unavailable` in the weekly stream file.
|
|
94
|
+
- Do NOT discard list-level evidence. Do NOT loop on broad fallback queries trying to rescue bodies.
|
|
95
|
+
|
|
96
|
+
## Two-pass pull (REQUIRED — no single-call summarization)
|
|
32
97
|
|
|
33
|
-
|
|
98
|
+
Same anti-summarization pattern as `pull-onenote` v2.2.0. WorkIQ summarizes by default — relying on a single "give me all emails this week" call returns a curated subset, not the full set. Doctrine: **enumerate the message list first, then fetch each message body individually.**
|
|
34
99
|
|
|
35
|
-
|
|
100
|
+
### Step A — Enumerate the message list
|
|
36
101
|
|
|
37
|
-
|
|
102
|
+
For each `boundaries.email.mailboxes[i]` × the date window (and optional sender_domains / subject_keywords):
|
|
38
103
|
|
|
39
|
-
|
|
104
|
+
```
|
|
105
|
+
workiq ask -q "List EVERY email in mailbox <mb> received between <start> and <end> [filtered to senders @<domain>] [containing subject keyword <kw>]. Return one row per message: messageId, internetMessageId, conversationId, sentDate, fromAddress, toAddresses, ccAddresses, subject, hasAttachments, sizeKB. Do NOT summarize, do NOT omit, do NOT group by thread yet, do NOT add commentary. Flat table only."
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
If the response is summarized (heuristics: `"and N more"`, `"sample"`, row count noticeably less than expected, message bodies included instead of just the index): **retry once** with `Return as a flat table with no commentary, no grouping, no truncation. Message count must equal the actual count in the date window.`
|
|
109
|
+
|
|
110
|
+
Persist the enumerated list to `Evidence/<alias>/email/_index/<YYYY-MM-DD>_message-index.md` (date = Monday of the ISO week). This makes the run idempotent + resumable.
|
|
111
|
+
|
|
112
|
+
### Step B — Per-message body fetch (one WorkIQ call per message)
|
|
113
|
+
|
|
114
|
+
For each message in the index, ONE WorkIQ call (per `workiq-only.instructions.md`):
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
workiq ask -q "Get the FULL body of email with messageId <id> (mailbox <mb>). Return: full text body verbatim (no summarization, no truncation), all headers (from, to, cc, bcc, sentDate, subject, conversationId, internetMessageId, references, in-reply-to), attachment list (filename + size + mimetype, do NOT download binary), and any inline images as alt text or skip with marker."
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**FORBIDDEN** (per workiq-only): `m365_get_email`, `m365_search_emails`, `m365_list_emails`, Graph REST. Do NOT add them as fallbacks. If WorkIQ body fetch fails, use the doubled-strict retry then user-paste — NEVER fall through to a host m365_* call.
|
|
121
|
+
|
|
122
|
+
If body comes back < 200 chars or includes phrases like `"unable to retrieve"`, `"body unavailable"`, `"truncated"`: doubled-strict retry once with `Return the raw email body, no summary, no truncation. If you cannot return the full body, say "body-unavailable" exactly and nothing else.` On second failure, record that message as `❌ body-unavailable` in the weekly stream file + continue (or prompt user to paste — first-class evidence path per workiq-only).
|
|
123
|
+
|
|
124
|
+
### Step C — Group by conversationId into threads
|
|
125
|
+
|
|
126
|
+
After all bodies fetched, group messages by `conversationId`. For each thread:
|
|
127
|
+
|
|
128
|
+
- Sort by `sentDate` ascending.
|
|
129
|
+
- Write a `## Thread: <subject>` block in the weekly stream file with:
|
|
130
|
+
- **AI Narrative Summary (REQUIRED FIRST, 3+ paragraphs)** — conversation arc, who's pushing what, decisions, asks, tone (per `evidence-thoroughness.instructions.md`).
|
|
131
|
+
- One `### Message <N> — <fromAddress> (<sentDate>)` block per message with: full headers (to/cc/subject), full body verbatim as a blockquote, attachment list.
|
|
132
|
+
- Append the thread block to the weekly file (`<YYYY-MM-DD>_email-stream.md`, date = Monday of the ISO week).
|
|
133
|
+
|
|
134
|
+
## Snapshot pass
|
|
135
|
+
|
|
136
|
+
_(no snapshot for email — emails are inherently event-stream)_
|
|
137
|
+
|
|
138
|
+
## Stream pass output
|
|
40
139
|
|
|
41
140
|
Write to: `<engagement-root>/<project>/Evidence/<alias>/email/stream/<YYYY-MM-DD>_email-stream.md` (date = Monday of the ISO week the events fall in).
|
|
42
141
|
|
|
142
|
+
Write the message index to: `<engagement-root>/<project>/Evidence/<alias>/email/_index/<YYYY-MM-DD>_message-index.md`.
|
|
143
|
+
|
|
43
144
|
Use template: `templates/weekly/email-summary.template.md`
|
|
44
145
|
|
|
45
|
-
If a week file already exists, MERGE (dedupe by
|
|
146
|
+
If a week file already exists, MERGE (dedupe by `internetMessageId`, append new threads, keep existing).
|
|
147
|
+
|
|
148
|
+
## Tools (WorkIQ ONLY — per `workiq-only.instructions.md`)
|
|
46
149
|
|
|
47
|
-
|
|
150
|
+
1. **WorkIQ (`workiq ask`)** — the ONLY allowed path for both enumeration (Step A) and per-message body fetch (Step B). Always include the boundary keys + the verbatim/no-summary phrasing. Use the canonical prompts codified in `plugin/instructions/workiq-only.instructions.md` (Email Bodies section) — do NOT re-derive them.
|
|
151
|
+
2. **Ask user (paste verbatim)** — first-class fallback when WorkIQ doubled-strict retry fails or returns `body-unavailable`. NOT a degradation; coverage.md labels it `Source: User paste on <ISO>`.
|
|
48
152
|
|
|
49
|
-
|
|
50
|
-
2. **Host fallback** — `m365_search_emails` / `m365_list_emails` scoped to `m365Auth.emailContext.folders`
|
|
51
|
-
3. **Graph REST** — last resort, soft-fail per `az-auth-conditional.instructions.md`.
|
|
52
|
-
4. **Ask user** — paste verbatim source content if all above fail.
|
|
153
|
+
**FORBIDDEN** for this skill (per workiq-only.instructions.md): `m365_get_email`, `m365_search_emails`, `m365_list_emails`, `m365_list_mail_folders`, `m365_search_mail`, Graph REST `https://graph.microsoft.com/v1.0/me/messages*`, Graph REST `https://graph.microsoft.com/v1.0/me/mailFolders*`. These tools have a near-100% failure rate in this workspace. Calling them is a DEFECT; coverage.md must NOT show them in the attempt trail.
|
|
53
154
|
|
|
54
|
-
Document which
|
|
155
|
+
Document the WorkIQ request-id + the exact prompt + which boundary was applied under `## Source Basis` in each output file (per workiq-only coverage.md requirements).
|
|
55
156
|
|
|
56
157
|
## Mutable hints to upsert (during the run, not at the end)
|
|
57
158
|
|
|
58
|
-
If discovered, immediately write to `m365Mutable.knownSections.<project>.<source>` with `discoveredOn` + `confidence
|
|
159
|
+
If discovered, immediately write to `m365Mutable.knownSections.<project>.<source>` with `discoveredOn` + `confidence`. Mandatory in EVERY run mode (bootstrap, refresh, retry):
|
|
59
160
|
|
|
60
|
-
- `emailContext.folder` — full path of the project's email folder
|
|
161
|
+
- `emailContext.folder` — full path of the project's email folder (upsert only when `confidence >= medium`)
|
|
61
162
|
- `emailContext.folderId` — folder ID for direct lookup
|
|
163
|
+
- `emailContext.lastFastPathUsed` — boolean; whether Order 1 succeeded this run
|
|
164
|
+
|
|
165
|
+
Upsert only confident folder mappings. Do not write low-confidence guesses — that pollutes the hint cache and degrades future fast-path success.
|
|
62
166
|
|
|
63
167
|
## Update run-log
|
|
64
168
|
|
|
65
169
|
After successful pass:
|
|
66
170
|
- `sources.email.last_pulled = now`
|
|
67
|
-
- `sources.email.watermark = now`
|
|
68
|
-
- `sources.email.
|
|
171
|
+
- `sources.email.watermark = now`
|
|
172
|
+
- `sources.email.coverage_state = ok | degraded-list-only | throttled-tooManyRequests | unavailable`
|
|
173
|
+
- `sources.email.retrieval_path = fast-folder | fast-folder-retry | root-fallback`
|
|
174
|
+
- `sources.email.messages_enumerated = <N>` — total messages discovered in scope
|
|
175
|
+
- `sources.email.messages_fetched = <N>` — total messages with full body captured
|
|
176
|
+
- `sources.email.messages_failed = <N>` — `body-unavailable` count
|
|
177
|
+
- `sources.email.threads = <N>` — number of conversations grouped
|
|
69
178
|
- For each week touched, add to `weekly_files` index.
|
|
70
179
|
|
|
180
|
+
## Depth bar (per `evidence-thoroughness.instructions.md`)
|
|
181
|
+
|
|
182
|
+
The pre-Step-C anti-summary doctrine + the Step-C AI Narrative Summary per thread together produce the depth users expect. Empty thread bodies are a defect — if Step B couldn't fetch a body, the message gets a `❌ body-unavailable` marker, NOT a paraphrase from the index row.
|
|
183
|
+
|
|
184
|
+
**Completeness bar:** `messages_enumerated` should equal `messages_fetched + messages_failed`. Drift surfaces in run-log; consolidate skill renders it as a Coverage Note.
|
|
185
|
+
|
|
71
186
|
## Stop conditions
|
|
72
187
|
|
|
188
|
+
- Boundary missing → refuse (see Boundaries above).
|
|
73
189
|
- Hint missing AND fuzzy resolution returns 0 candidates → ask user once, persist answer to mutable, continue.
|
|
74
|
-
-
|
|
75
|
-
-
|
|
190
|
+
- Enumeration step (Step A) failed → write `_index/<date>_message-index.md` with failure marker, log to run-log errors, do NOT proceed to per-message loop.
|
|
191
|
+
- Per-message fetch failed → record marker, continue.
|
|
192
|
+
- All paths failed → write evidence file with `❌ all paths failed` marker, log to run-log errors, continue with rest of run.
|
|
@@ -1,17 +1,29 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "pull-meetings"
|
|
3
|
-
version: "2.1
|
|
4
|
-
description: "Pull Meetings evidence
|
|
3
|
+
version: "2.2.1"
|
|
4
|
+
description: "Pull Meetings evidence in THREE shapes: snapshot/ series-index, stream/ per-meeting curated blocks, AND verbatim/ raw immutable folder per meeting (meetings expire — verbatim/ MUST contain the full transcript text, not just chat). v2.4.0: WorkIQ-ONLY for transcript capture per workiq-only.instructions.md (m365_get_transcript / Graph REST FORBIDDEN — they have near-100% failure rate in this workspace). Chat is parallel supporting evidence (via m365_list_chat_messages structured dump), NEVER a transcript substitute."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Skill: pull-meetings
|
|
8
8
|
|
|
9
|
-
Pulls **meetings** evidence in two shapes per `snapshot-vs-stream.instructions.md`:
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
-
|
|
10
|
+
> **v3.7.6 + v3.10.0 + v3.11.0 contracts** — This skill operates under six HARD-rule doctrines:
|
|
11
|
+
> - `verbatim-by-default.instructions.md` — full bodies/notetext/fields by default; no preview-grade pulls accepted.
|
|
12
|
+
> - `meetings-verbatim-required.instructions.md` (v3.10.0) — meetings are an EXPIRING evidence class; every captured meeting MUST also produce a sibling `verbatim/<YYYY-MM-DD-HHMM>_<slug>/` folder with raw chat + transcript + recording URL. Curated snapshot alone is a defect.
|
|
13
|
+
> - **`workiq-only.instructions.md` (v3.11.0)** — transcripts, facilitator notes, calendar discovery, and chat-thread human rendering go through WorkIQ ONLY. `m365_get_transcript`, `m365_get_facilitator_notes`, `m365_list_meetings`, `m365_list_events`, and Graph REST URLs are FORBIDDEN as fallbacks (they fail nearly every call). The canonical WorkIQ prompts are codified in that instruction — do not re-discover them.
|
|
14
|
+
> - `capture-learnings.instructions.md` — every fix/discovery is logged to `plugin/learnings/<source>.md` immediately.
|
|
15
|
+
> - `cleanup-on-resolution.instructions.md` — when a value resolves, all stale `no-match` / `not yet` notes referencing the prior unresolved state must be rewritten in the same turn.
|
|
16
|
+
> - `run-reports.instructions.md` — every refresh writes a per-user report under `Evidence/<alias>/refresh-reports/YYYY-MM-DD-HHMM_refresh.md`.
|
|
13
17
|
|
|
14
|
-
|
|
18
|
+
> **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`.
|
|
19
|
+
|
|
20
|
+
Pulls **meetings** evidence in three shapes per `snapshot-vs-stream.instructions.md` + `meetings-verbatim-required.instructions.md`:
|
|
21
|
+
|
|
22
|
+
- **snapshot/** — `series-index.md` listing all recurring meeting series for this project (subject, recurrence, organizer, current attendees)
|
|
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
|
+
- **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
|
+
|
|
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-detector.instructions.md`. Citations per `citation-ledger.instructions.md`.
|
|
15
27
|
|
|
16
28
|
## Inputs
|
|
17
29
|
|
|
@@ -20,39 +32,110 @@ Auth + retry + error logging per `auth-and-retry.instructions.md`. WorkIQ-first
|
|
|
20
32
|
- `<window>` — date range. For snapshot: ignored (always full re-fetch). For stream: `(from, to)`.
|
|
21
33
|
- (read) `<engagement-root>/.project-evidence/m365/m365-mutable.json m365Mutable.knownSections.<project>` — pinned hints (`calendarContext.subjectKeywords`, `calendarContext.knownSeries`).
|
|
22
34
|
|
|
23
|
-
## Discovery (snapshot pass)
|
|
35
|
+
## Discovery (snapshot pass — WorkIQ ONLY per `workiq-only.instructions.md`)
|
|
24
36
|
|
|
25
|
-
1.
|
|
26
|
-
|
|
27
|
-
|
|
37
|
+
1. **WorkIQ meeting discovery** (canonical prompt from `workiq-only.instructions.md` Calendar/online meetings section):
|
|
38
|
+
> `List my Teams meetings between <start> and <end> where the subject contains "<token>". Return subject, date, start time, organizer, joinUrl, and Teams chat id.`
|
|
39
|
+
- Issued ONCE per token in `calendarContext.subjectKeywords`.
|
|
40
|
+
- For each match: capture `subject`, `start`, `end`, `organizer`, `joinUrl`, `chatId`. Persist to mutable as `calendarContext.knownSeries[]`.
|
|
41
|
+
2. Cross-reference returned `chatId` values with `boundaries.teams.chat_ids[]` — every meeting whose chat-id falls inside the teams boundary is treated as in-scope. This enriches each meeting with the attendee roster the `pull-teams` snapshot already captured.
|
|
42
|
+
|
|
43
|
+
**FORBIDDEN** for discovery: `m365_list_meetings`, `m365_list_events`, Graph REST `/me/calendar/events`, Graph REST `/me/onlineMeetings`. Use WorkIQ.
|
|
28
44
|
|
|
29
45
|
Write `snapshot/series-index.md` listing all matched series. Updated every refresh (organizers/attendees may change).
|
|
30
46
|
|
|
31
|
-
##
|
|
47
|
+
## Boundaries (REQUIRED — see `scope-boundaries.instructions.md`)
|
|
48
|
+
|
|
49
|
+
This skill REFUSES to query unless `<engagement-root>/<project>/integrations.yml#boundaries.meetings` is satisfied:
|
|
50
|
+
|
|
51
|
+
- `boundaries.meetings.series_join_urls` — REQUIRED, non-empty (pinned join URLs; no subject-keyword fuzz).
|
|
52
|
+
- `boundaries.meetings.organizer_emails` — optional additional filter.
|
|
53
|
+
- `boundaries.date_window_days` — defaults to 30 if absent.
|
|
54
|
+
|
|
55
|
+
The pre-existing `subjectKeywords` / `knownSeries` discovery loop is now a **bootstrap-time aid only** — it helps populate `boundaries.meetings.series_join_urls` once. At pull time, only meetings whose `joinUrl` is in the boundary list are processed.
|
|
56
|
+
|
|
57
|
+
Refusal message when boundary is missing:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
meetings-boundary-missing — add boundaries.meetings.series_join_urls to
|
|
61
|
+
<engagement-root>/<project>/integrations.yml. See doctrine in
|
|
62
|
+
plugin/instructions/scope-boundaries.instructions.md.
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Per-meeting capture cascade — verbatim/ FIRST, then curated stream
|
|
66
|
+
|
|
67
|
+
For EACH meeting in the window, the cascade has **two halves**: (A) write raw artifacts to `verbatim/<YYYY-MM-DD-HHMM>_<slug>/`, then (B) produce the curated stream block citing those verbatim files. Half A is mandatory before Half B per `meetings-verbatim-required.instructions.md`.
|
|
68
|
+
|
|
69
|
+
### Half A — verbatim/ capture (REQUIRED, transcript-first, WorkIQ-only per workiq-only.instructions.md)
|
|
70
|
+
|
|
71
|
+
For every meeting, BEFORE writing any curated text:
|
|
72
|
+
|
|
73
|
+
0. Compute slug + timestamp, create `Evidence/<alias>/meetings/verbatim/<YYYY-MM-DD-HHMM>_<slug>/`, write `captured-at.txt` (started_at, kushi_version).
|
|
32
74
|
|
|
33
|
-
|
|
75
|
+
1. **Transcript cascade — WorkIQ-only, EXHAUSTIVE, in order. Do NOT stop at first weak result; record each path's result in `coverage.md`.** Per `meetings-verbatim-required.instructions.md` "Transcript capture cascade":
|
|
76
|
+
- **a. WorkIQ full-transcript pull (REQUIRED first attempt)** with the canonical prompt from `workiq-only.instructions.md`:
|
|
77
|
+
> `Find the Teams meeting titled "<subject>" that occurred on <YYYY-MM-DD>. Return the full transcript verbatim with speaker labels and timestamps. Do not summarize.`
|
|
78
|
+
- If WorkIQ returns full speaker-turn text (≥ ~10 distinct `Name:` lines) → strip `request-id:` prefix, save body as `transcript.txt` with header (source, query, request-id, fidelity).
|
|
79
|
+
- If WorkIQ returns a summary (paragraphs only, no speaker turns) → run the **doubled-strict retry** from `workiq-only.instructions.md` once. If still summary-only, save as `transcript-source.md` with the `WARNING: NOT a verbatim transcript` header.
|
|
80
|
+
- **b. WorkIQ Copilot recap (SUPPLEMENTARY, always attempt)**:
|
|
81
|
+
> `Get the Copilot meeting recap (decisions, action items, key points) for the Teams meeting "<subject>" on <YYYY-MM-DD>. Return the FULL recap card verbatim. Do not summarize.`
|
|
82
|
+
- Save as `facilitator-notes.md`. Supplementary; does NOT replace the transcript.
|
|
83
|
+
- **c. WorkIQ recording-URL discovery**:
|
|
84
|
+
> `For the meeting "<subject>" on <YYYY-MM-DD>, return the SharePoint Stream recording URL if it exists, and the calendar event body.`
|
|
85
|
+
- Save URL(s) to `recording-url.txt`. If a `.mp4` URL is present, downloading the recording binary is governed by the `pull-meetings` recording-download carve-out (size < 200MB) — this is the ONLY allowed `m365_download_file` call in any kushi pull-* skill, because the recording is binary media and WorkIQ does not download binaries.
|
|
86
|
+
- **d. User-paste fallback (first-class, NOT a degradation)** — when (a) returns empty/`body-unavailable` after doubled-strict retry AND (b) returns nothing usable: prompt the user to paste verbatim transcript or notes. Save to `transcript.txt` with header `User-pasted; WorkIQ returned no transcript on <ISO timestamp>`.
|
|
34
87
|
|
|
35
|
-
|
|
36
|
-
2. **`m365_get_transcript`** with the meeting's `joinUrl`.
|
|
37
|
-
3. **Reconstruction from chat** (NOT a failure — first-class fallback). When transcripts simply don't exist (transcription was off, or VTT not yet attached), reconstruct evidence from:
|
|
38
|
-
- Meeting chat thread: `m365_list_chat_messages(chatId)` — captured already by `pull-teams`.
|
|
39
|
-
- Pre/post-meeting context messages.
|
|
40
|
-
- Any Copilot recap card posted to the chat.
|
|
41
|
-
Mark the per-meeting block `Source basis: reconstructed from meeting chat (no transcript)`. This is **evidence**, not a gap.
|
|
42
|
-
4. **Ask user**: paste verbatim transcript or notes if all above produced nothing usable.
|
|
88
|
+
**FORBIDDEN** (do NOT attempt; do NOT log as cascade steps in coverage.md): `m365_get_transcript`, `m365_get_facilitator_notes`, `m365_list_meetings`, `m365_list_events`, Graph REST `/me/onlineMeetings/.../transcripts/.../content`. These have a near-100% failure rate in this workspace and pollute the coverage trail. Use WorkIQ steps (a)/(b)/(c).
|
|
43
89
|
|
|
44
|
-
|
|
90
|
+
2. **Chat capture (ALWAYS, parallel with step 1 — allowed exception to workiq-only)**: `m365_list_chat_messages(chatId)` → `chat-messages.json` (raw structured-data dump) + `chat-messages.md` (rendered, one heading-block per message). Chat is **supporting evidence**; it is **NEVER** a transcript substitute. If `m365_list_chat_messages` fails, run the WorkIQ chat-thread prompt as fallback (per `workiq-only.instructions.md` Teams chat thread section).
|
|
91
|
+
|
|
92
|
+
3. Walk chat for attachments → `m365_download_file` each → `attachments/<original-name>` (binary download carve-out, same as recording.mp4).
|
|
93
|
+
|
|
94
|
+
4. Walk chat for Copilot recap card → `recap-card.md` verbatim.
|
|
95
|
+
|
|
96
|
+
5. **Classify** the verbatim folder per the doctrine:
|
|
97
|
+
- `transcript-complete` — at least one of `transcript.vtt` / `transcript.txt` / `transcript-source.md` is non-empty.
|
|
98
|
+
- `transcript-missing` — only `chat-messages.*` present; all WorkIQ cascade paths (1a–1d) returned empty.
|
|
99
|
+
|
|
100
|
+
6. Write `coverage.md` with classification + per-path attempt log (every WorkIQ path attempted, with request-id, even successful ones) + source-basis classification for stream/.
|
|
101
|
+
|
|
102
|
+
7. Update `captured-at.txt` with `completed_at` + `final_status` (one of `transcript-complete-text` / `transcript-complete-summary-only` / `transcript-missing-chat-only` / `unrecoverable`).
|
|
103
|
+
|
|
104
|
+
If 1a–1d ALL return empty AND step 2 chat is also empty AND user paste is declined → `unrecoverable`. Apply retry pattern per `auth-and-retry.instructions.md`.
|
|
105
|
+
|
|
106
|
+
### Half B — curated stream/ block (cites verbatim/)
|
|
107
|
+
|
|
108
|
+
Build the per-meeting block in `stream/<week>_meetings-stream.md` using ONLY content already persisted in verbatim/. Every assertion cites a verbatim file. Preferred citation chain:
|
|
109
|
+
- `[source: Evidence/<alias>/meetings/verbatim/<dir>/transcript.vtt · <date>]` when transcript-complete-vtt.
|
|
110
|
+
- `[source: Evidence/<alias>/meetings/verbatim/<dir>/transcript.txt · <date>]` when transcript-complete-text.
|
|
111
|
+
- `[source: Evidence/<alias>/meetings/verbatim/<dir>/transcript-source.md · <date>]` when only Copilot summary (always note the warning).
|
|
112
|
+
- `[source: Evidence/<alias>/meetings/verbatim/<dir>/chat-messages.md · <date>]` only for assertions backed by chat (not transcript content).
|
|
113
|
+
|
|
114
|
+
`Source basis` line in the curated block reflects verbatim classification:
|
|
115
|
+
- `transcript (raw VTT)` — transcript.vtt present
|
|
116
|
+
- `transcript (plain text)` — transcript.txt present, no VTT
|
|
117
|
+
- `transcript (WorkIQ Copilot summary — NOT verbatim)` — only transcript-source.md
|
|
118
|
+
- `❌ no-transcript-recovered-chat-only` — only chat-messages.*
|
|
119
|
+
- `❌ unrecoverable` — only captured-at.txt + coverage.md
|
|
120
|
+
|
|
121
|
+
A meeting with `transcript-missing-chat-only` is valid evidence in a degraded sense — actions/decisions citeable from chat are still useful — but the curated block MUST flag the gap prominently and the run-log MUST record `transcript-unrecoverable` for that meeting.
|
|
122
|
+
|
|
123
|
+
### Ask-user fallback
|
|
124
|
+
|
|
125
|
+
When the entire cascade (1a–1d + chat) produces nothing usable, ask the user to paste verbatim transcript or notes. Persist any paste to `verbatim/<dir>/transcript.txt` with header `User-pasted; automated paths returned no transcript on <ISO timestamp>`.
|
|
45
126
|
|
|
46
127
|
## Stream pass
|
|
47
128
|
|
|
48
|
-
Per `evidence-thoroughness.instructions.md`: every meeting in the window gets a full per-meeting block. **A 30-line meetings file for a week with 2 meetings is a defect — expect
|
|
129
|
+
Per `evidence-thoroughness.instructions.md`: every meeting in the window gets a full per-meeting block whose **FIRST sub-section is an AI Narrative Summary (REQUIRED, 5+ paragraphs)** covering the whole meeting end-to-end — context, what was discussed in what order, who took which position, the reasoning, the back-and-forth, soft signals, sentiment, what landed and what stayed open (cited to transcript timestamps). Then attendees → agenda → Detailed Discussion Summary (topic-organized) → chronological transcript walk-through with verbatim quotes → Decisions → Open Questions → Next Steps → Action Items → Risks → Customer Asks → Coverage Notes. **A 30-line meetings file for a week with 2 meetings is a defect — expect 300+ lines (the AI Narrative Summary alone is typically 30-50 lines per meeting).** A per-meeting block missing the AI Narrative Summary as the first sub-section is a defect even if every other section is present.
|
|
49
130
|
|
|
50
131
|
Write to: `<engagement-root>/<project>/Evidence/<alias>/Meetings/stream/<YYYY-MM-DD>_meetings-stream.md` (date = Monday of the ISO week).
|
|
51
132
|
|
|
52
|
-
Use template: `templates/weekly/meetings-
|
|
133
|
+
Use template: `templates/weekly/meetings-stream.template.md`
|
|
53
134
|
|
|
54
135
|
If a week file already exists, MERGE (dedupe by event ID, append new events, keep existing).
|
|
55
136
|
|
|
137
|
+
**Verbatim sibling required.** Every per-meeting block written here MUST have a matching `Evidence/<alias>/meetings/verbatim/<YYYY-MM-DD-HHMM>_<slug>/` folder produced by Half A. The block's `Source basis` line and `Artifacts` section must cite the verbatim folder's relative path. Self-check D13 enforces this.
|
|
138
|
+
|
|
56
139
|
## Mutable hints to upsert (during the run, not at the end)
|
|
57
140
|
|
|
58
141
|
If discovered, immediately write to `m365Mutable.knownSections.<project>.calendarContext` with `discoveredOn` + `confidence`:
|
|
@@ -73,5 +156,6 @@ After the pass:
|
|
|
73
156
|
## Stop conditions
|
|
74
157
|
|
|
75
158
|
- Subject keyword resolution returns 0 candidates → ask user once for keywords, persist to mutable, continue.
|
|
76
|
-
- A meeting has neither transcript NOR chat messages → write `❌
|
|
77
|
-
- All paths failed for ALL meetings in the window → mark source `failed`, write a single `❌ all paths failed` evidence file with actionable next step.
|
|
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
|
+
- 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
|
+
- 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.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# pull-misc runner
|
|
2
|
+
|
|
3
|
+
Pulls evidence from a user-curated link list (`<project>/external-links.txt`). Handles types that don't fit a dedicated `pull-*` skill: Loop pages, public web pages, learn.microsoft.com / docs sites, GitHub repos, local files. Delegated types (onenote, sharepoint, ado) are recorded as `delegated` and pulled by their dedicated skills.
|
|
4
|
+
|
|
5
|
+
See `SKILL.md` for the full doctrine.
|
|
6
|
+
|
|
7
|
+
## One-time setup
|
|
8
|
+
|
|
9
|
+
```pwsh
|
|
10
|
+
# Install deps in the kushi repo
|
|
11
|
+
cd C:\Usha\ISERepos\kushi
|
|
12
|
+
npm install playwright jsdom @mozilla/readability
|
|
13
|
+
npx playwright install chromium
|
|
14
|
+
|
|
15
|
+
# (Loop links only) Seed the Playwright profile by reusing the OneNote profile
|
|
16
|
+
# If you've already done OneNote bootstrap, you're done — Loop reuses it.
|
|
17
|
+
node plugin/skills/pull-onenote/runner.mjs --bootstrap
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Per-project run
|
|
21
|
+
|
|
22
|
+
```pwsh
|
|
23
|
+
node plugin/skills/pull-misc/runner.mjs `
|
|
24
|
+
--project "ABN AMRO" `
|
|
25
|
+
--links-file "C:\Users\ushak\OneDrive - Microsoft\ISE\Engagement Assets\ABN AMRO\external-links.txt" `
|
|
26
|
+
--engagement-root "C:\Users\ushak\OneDrive - Microsoft\ISE\Engagement Assets" `
|
|
27
|
+
--headless
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Output
|
|
31
|
+
|
|
32
|
+
Single JSON object on stdout:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"project": "ABN AMRO",
|
|
37
|
+
"linksFile": "...",
|
|
38
|
+
"runStatus": "ok | auth-required | partial",
|
|
39
|
+
"counts": {
|
|
40
|
+
"total": 12,
|
|
41
|
+
"captured": 8,
|
|
42
|
+
"placeholder": 2,
|
|
43
|
+
"delegated": 1,
|
|
44
|
+
"auth_required": 0,
|
|
45
|
+
"fetch_failed": 1,
|
|
46
|
+
"skipped_binary": 0
|
|
47
|
+
},
|
|
48
|
+
"links": [
|
|
49
|
+
{ "type": "web", "title": "...", "url": "...", "last_status": "captured", "captured_via": "http",
|
|
50
|
+
"http_status": 200, "content_type": "text/html", "etag": "...", "last_modified_http": "...",
|
|
51
|
+
"body": "...", "char_count": 18420, "captured_at": "..." }
|
|
52
|
+
/* ... */
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Filtering
|
|
58
|
+
|
|
59
|
+
```pwsh
|
|
60
|
+
# Only loop links
|
|
61
|
+
node runner.mjs --project ABN ... --types loop
|
|
62
|
+
|
|
63
|
+
# Only specific titles (substring match)
|
|
64
|
+
node runner.mjs --project ABN ... --titles "Workshop,Architecture"
|
|
65
|
+
|
|
66
|
+
# Combine
|
|
67
|
+
node runner.mjs --project ABN ... --types web,loop --titles "Architecture"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Scheduled / unattended runs
|
|
71
|
+
|
|
72
|
+
- Browser branch (loop) reuses `~/.copilot/playwright-profile/onenote/`. When MFA fires, runner marks loop links `auth-required` and exits cleanly. User does one interactive bootstrap; next scheduled run silent.
|
|
73
|
+
- HTTP branch needs no auth for public links. For sites behind SSO (auth'd Confluence, internal dashboards) it returns `auth-required` and is currently NOT supported — paste the content into a `file` link as a workaround, OR add a per-site auth handler in a future version.
|
|
74
|
+
- `placeholder` links surface in the run report every refresh until the user fills them in.
|
|
75
|
+
|
|
76
|
+
## Troubleshooting
|
|
77
|
+
|
|
78
|
+
| Symptom | Cause | Fix |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `Cannot find module 'jsdom'` | deps not installed | `npm install jsdom @mozilla/readability` in repo root |
|
|
81
|
+
| All loop links `auth-required` | profile expired | `node plugin/skills/pull-onenote/runner.mjs --bootstrap` |
|
|
82
|
+
| `web` link returns near-empty body | site is SPA / requires JS render | Add it as a `loop` type to use browser path; or paste content as `file` |
|
|
83
|
+
| `confluence` link returns auth-required | private Confluence, no anon access | not supported in v0.1; paste content as `file` |
|
|
84
|
+
| `pdf` link returns "text extraction not yet implemented" | pdfjs not bundled | text extract is a v0.2 item; manually extract for now |
|