kushi-agents 4.8.1 → 4.8.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kushi-agents",
3
- "version": "4.8.1",
3
+ "version": "4.8.3",
4
4
  "description": "Install Kushi — multi-source project evidence agent with snapshot+stream capture across Email, Teams, OneNote, Loop, SharePoint, Meetings, CRM, ADO. WorkIQ-only for M365 sources (Graph / m365_* FORBIDDEN as fallbacks; user-paste is first-class). Host-agnostic.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -44,7 +44,7 @@ For each source whose sweep runs:
44
44
 
45
45
  1. **Append discovered IDs / URLs / paths to `<engagement-root>/<project>/integrations.yml#boundaries.<source>.<key>`** as plain strings (existing pull-* skills consume strings — do NOT change the array element type). Idempotent: deduplicate by exact-string equality.
46
46
 
47
- 2. **Write a sidecar discovery record to `<engagement-root>/<project>/Evidence/_discovery/<YYYY-MM-DD>_<source>_discovery.yml`** with the per-row metadata (`discovered_by`, `discovered_at`, `needs_review`, `query`, `request_id`, `confidence`). Schema:
47
+ 2. **Write a sidecar discovery record to `<engagement-root>/<project>/Evidence/<alias>/_discovery/<YYYY-MM-DD>_<source>_discovery.yml`** with the per-row metadata (`discovered_by`, `discovered_at`, `needs_review`, `query`, `request_id`, `confidence`). The sidecar lives **inside the contributor's alias folder** because discovery results are inherently per-identity (each contributor sees a different mailbox / chat / meeting set). Schema:
48
48
 
49
49
  ```yaml
50
50
  source: email | teams | meetings | sharepoint
@@ -93,11 +93,12 @@ For each source whose sweep runs:
93
93
 
94
94
  ## Multi-contributor safety
95
95
 
96
- When the boundary already has rows from another alias (or the sidecar `Evidence/_discovery/` already has entries):
96
+ When the boundary already has rows from another alias (or sibling `Evidence/<other-alias>/_discovery/` folders already have entries):
97
97
 
98
98
  1. **Append-only** — the new alias's sweep adds rows that are not already present (dedupe by exact-string equality on the boundary value). Never remove or rewrite another alias's row.
99
- 2. **Sidecar file is per-source-per-date** — multiple contributors on the same day produce separate sidecar files (`2026-05-26_email_discovery-ushak.yml`, `2026-05-26_email_discovery-stand.yml`). Bootstrap-status's Discovery Sweep Results table shows one row per source × alias.
99
+ 2. **Sidecar files are per-contributor-folder-per-source-per-date** — each contributor writes only into their own `Evidence/<alias>/_discovery/` folder. Filenames are NOT suffixed with `-<alias>` (folder already namespaces the owner). On the same day, contributors `ushak` and `stand` produce `Evidence/ushak/_discovery/2026-05-26_email_discovery.yml` and `Evidence/stand/_discovery/2026-05-26_email_discovery.yml` respectively — no collision possible. Bootstrap-status's Discovery Sweep Results table shows one row per source × alias.
100
100
  3. **`Discovered by` column in bootstrap-status's per-source Context Artifact Status row** cites the most recent discovering alias. Preserve other aliases' rows in `## Contributors who have bootstrapped this project` per `multi-user-shared-files.instructions.md`.
101
+ 4. **NEVER write to another contributor's `Evidence/<other-alias>/_discovery/` folder.** Reading other aliases' discovery sidecars (e.g. to merge already-confirmed candidates into the shared boundary) is allowed and expected; writing into them is forbidden.
101
102
 
102
103
  ## Rerun behavior
103
104
 
@@ -55,7 +55,7 @@ WorkIQ returns a markdown table. Parse rows where `folder path` is non-empty and
55
55
 
56
56
  ## Sidecar file shape
57
57
 
58
- Written to `<engagement-root>/<project>/Evidence/_discovery/<YYYY-MM-DD>_email_discovery-<alias>.yml`:
58
+ Written to `<engagement-root>/<project>/Evidence/<alias>/_discovery/<YYYY-MM-DD>_email_discovery.yml` (per-contributor folder; no `-<alias>` filename suffix since the folder already namespaces the owner):
59
59
 
60
60
  ```yaml
61
61
  source: email
@@ -85,13 +85,13 @@ The `setup` skill (added v4.4.4) extends this doctrine beyond identity to cover
85
85
  | `project-evidence.yml` | `identity.alias` / `display_name` / `email` | YES | WorkIQ "Who am I?" |
86
86
  | `project-evidence.yml` | `identity_status`, `identity_verified_at` | YES | written by setup |
87
87
  | `project-evidence.yml` | `projects_root` | YES | cwd-ancestor detection; otherwise prompt |
88
- | `project-evidence.yml` | `default_onenote_notebook` | **OPTIONAL** | user prompt; value `<skip>` = OneNote disabled |
88
+ | `project-evidence.yml` | `default_onenote_notebook` | **DEPRECATED (display-only as of v4.8.3)** | display-only mirror of `m365-auth.json#oneNote.defaultNotebookName`. NEVER gates OneNote. The `<skip>` sentinel is deprecated. |
89
89
  | `project-evidence.yml` | `active_projects[]` | YES (list, may be empty) | the project arg if dispatched from `bootstrap <project>`; otherwise leave existing |
90
90
  | `project-evidence.yml` | `workiq.cli_path` | OPTIONAL | only written when discovered via PATH/fallback, not already pinned |
91
91
  | `m365-auth.json` | `_meta.owner` | YES | `<identity.email>` |
92
92
  | `m365-auth.json` | `oneNote.defaultLinkOwner` | YES (when OneNote enabled) | `<identity.email>` — the user's own UPN, since OneNote queries default to the user's personal notebook |
93
93
  | `m365-auth.json` | `oneNote.defaultNotebookId` | **NOT WRITTEN (kushi v4.7.3+)** | Per `workiq-onenote-query-shape.instructions.md`, WorkIQ has no notebook-ID lookup surface — any such probe punts to Graph Explorer. Setup persists `defaultNotebookName` only; section IDs are discovered per-section at bootstrap/refresh time using the natural-language WorkIQ pattern. |
94
- | `m365-auth.json` | `oneNote.enabled` | YES | `false` when user chose `<skip>` for the notebook name |
94
+ | `m365-auth.json` | `oneNote.enabled` | YES | **default `true` (kushi v4.8.3+).** Single source of truth — the only field that gates OneNote across kushi. Set to `false` ONLY when the contributor explicitly opts out via `setup` or by hand. The legacy `project-evidence.yml#default_onenote_notebook == "<skip>"` sentinel is deprecated and no longer consulted. |
95
95
  | `m365-auth.json` | `emailContext.folders[]` | OPTIONAL | user prompt: comma-sep list / `all` / blank. `all` or blank → `[]` (full mailbox) |
96
96
  | `m365-auth.json` | `sharePointContext.localProjectsRoot` | YES | mirrors `<projects_root>` |
97
97
 
@@ -101,10 +101,12 @@ The `setup` skill (added v4.4.4) extends this doctrine beyond identity to cover
101
101
 
102
102
  The `setup` skill does the deeper recovery (3-retry loop with `ask_user` choices).
103
103
 
104
- ### OneNote — optional + auto-resolve
104
+ ### OneNote — enabled by default, single switch (kushi v4.8.3+)
105
105
 
106
- - User chose `<skip>` → set `oneNote.enabled: false`, leave all other OneNote fields blank, OneNote source becomes a no-op (reported as `not-applicable` in run logs).
107
- - User gave a notebook name query WorkIQ for `{notebookId, notebookSourceDoc, notebookSpoBaseUrl}`. Persist all three. If WorkIQ returns empty, leave `defaultNotebookId: ""` with a `_defaultNotebookId_note` and let `pull-onenote` Step A do per-section discovery.
106
+ - **Default:** `m365Auth.oneNote.enabled: true`. OneNote is opt-out, not opt-in.
107
+ - **Single source of truth:** `m365Auth.oneNote.enabled` is the ONLY field that gates OneNote across kushi. Downstream skills (`pull-onenote`, `bootstrap-project` Step 4) MUST NOT inspect `project-evidence.yml#default_onenote_notebook` to decide whether to run OneNote.
108
+ - User explicitly opted out → set `oneNote.enabled: false`, leave other OneNote fields blank, OneNote source becomes a no-op (reported as `not-applicable` in run logs). Re-enable by hand-editing `m365-auth.json` (`enabled: true`) or by running `setup --reconfigure`.
109
+ - User gave a notebook name (or accepted the `ISE Work` default) → keep `enabled: true`, persist `defaultNotebookName`. Do NOT query WorkIQ for the notebook ID (per `workiq-onenote-query-shape.instructions.md` — no notebook-inventory surface). Section IDs are discovered per-section at bootstrap/refresh time.
108
110
  - `defaultLinkOwner` is ALWAYS the user's own UPN unless the user explicitly overrides (shared/team-owned notebook case).
109
111
 
110
112
  ### Mailbox folders — multi-value with "all" sentinel
@@ -131,9 +133,10 @@ Both `all` and blank persist as `[]`. ALWAYS print after persisting:
131
133
  ```
132
134
  Edit these files later if anything changes:
133
135
  • <workspace>/.kushi/config/user/project-evidence.yml
134
- identity, projects_root, default_onenote_notebook, active_projects, workiq.cli_path
136
+ identity, projects_root, active_projects, workiq.cli_path
137
+ (default_onenote_notebook is display-only since v4.8.3 — edit m365-auth.json to enable/disable)
135
138
  • <workspace>/.kushi/config/user/m365-auth.json
136
- OneNote defaults, email folder list, SharePoint root
139
+ OneNote enable/disable + notebook name (oneNote.enabled, oneNote.defaultNotebookName), email folder list, SharePoint root
137
140
  • <workspace>/.kushi/config/shared/integrations.yml (team-wide; commit changes)
138
141
  CRM environmentUrl + tenantId, ADO organization + project
139
142
 
@@ -60,7 +60,7 @@ This phrasing — **natural-language by subject + organizer + join URL request**
60
60
 
61
61
  ## Sidecar file shape
62
62
 
63
- Written to `<engagement-root>/<project>/Evidence/_discovery/<YYYY-MM-DD>_meetings_discovery-<alias>.yml`. Schema per `email-bootstrap-discovery.instructions.md` § Sidecar file shape, with `source: meetings`.
63
+ Written to `<engagement-root>/<project>/Evidence/<alias>/_discovery/<YYYY-MM-DD>_meetings_discovery.yml` (per-contributor folder; no `-<alias>` filename suffix). Schema per `email-bootstrap-discovery.instructions.md` § Sidecar file shape, with `source: meetings`.
64
64
 
65
65
  Additional field for meetings sidecar:
66
66
 
@@ -67,7 +67,7 @@ WorkIQ commonly punts on this query (see Empirical finding above). Apply this cl
67
67
 
68
68
  ## Sidecar file shape
69
69
 
70
- Written to `<engagement-root>/<project>/Evidence/_discovery/<YYYY-MM-DD>_sharepoint_discovery-<alias>.yml`. Schema per `email-bootstrap-discovery.instructions.md` § Sidecar file shape, with `source: sharepoint`.
70
+ Written to `<engagement-root>/<project>/Evidence/<alias>/_discovery/<YYYY-MM-DD>_sharepoint_discovery.yml` (per-contributor folder; no `-<alias>` filename suffix). Schema per `email-bootstrap-discovery.instructions.md` § Sidecar file shape, with `source: sharepoint`.
71
71
 
72
72
  ```yaml
73
73
  results:
@@ -87,7 +87,7 @@ WorkIQ returns the `chat ID` column populated as `N/A` (empirical, v4.8.1). The
87
87
 
88
88
  ## Sidecar file shape
89
89
 
90
- Two sidecar files (one per query). Written to `<engagement-root>/<project>/Evidence/_discovery/<YYYY-MM-DD>_teams-chats_discovery-<alias>.yml` and `<YYYY-MM-DD>_teams-channels_discovery-<alias>.yml`.
90
+ Two sidecar files (one per query). Written to `<engagement-root>/<project>/Evidence/<alias>/_discovery/<YYYY-MM-DD>_teams-chats_discovery.yml` and `<engagement-root>/<project>/Evidence/<alias>/_discovery/<YYYY-MM-DD>_teams-channels_discovery.yml` (per-contributor folder; no `-<alias>` filename suffix since the folder already namespaces the owner).
91
91
 
92
92
  Schema is the same as `email-bootstrap-discovery.instructions.md` § Sidecar file shape, with `source: teams-chats` or `source: teams-channels`.
93
93
 
@@ -138,7 +138,7 @@ For each sweep:
138
138
  3. Parse the response per the doctrine's parsing rules.
139
139
  4. Cap at 10 candidates by recency (or per-doctrine ordering).
140
140
  5. Append discovered values to `<project>/integrations.yml#boundaries.<source>.<key>` as plain strings (deduplicate by exact-string equality).
141
- 6. Write sidecar `<project>/Evidence/_discovery/<YYYY-MM-DD>_<source>_discovery-<alias>.yml` with per-row metadata (`discovered_by`, `discovered_at`, `needs_review: true`, `confidence`, `query`, `workiq_request_id`).
141
+ 6. Write sidecar `<project>/Evidence/<alias>/_discovery/<YYYY-MM-DD>_<source>_discovery.yml` with per-row metadata (`discovered_by`, `discovered_at`, `needs_review: true`, `confidence`, `query`, `workiq_request_id`). The sidecar lives INSIDE the contributor's alias folder (discovery results are per-identity); filename is NOT suffixed with `-<alias>` since the folder already namespaces the owner.
142
142
  7. If `> 10` candidates: append the remainder to `<project>/OPEN-QUESTIONS-DRAFT.md` under `## Discovery sweep — candidates over cap`.
143
143
  8. If `0` candidates: write `last_status: unresolved` (NOT `blocked-config`) and append a one-line widen-hint suggestion to Open Questions.
144
144
  9. If WorkIQ errors: write a `deferred-retry` marker per `deferred-retry-on-workiq-fail.instructions.md` and set `last_status: deferred`. Do NOT skip ahead to `blocked-config`.
@@ -126,24 +126,25 @@ Also write:
126
126
 
127
127
  Bootstrap + refresh MUST refuse to start if `projects_root_status` is `syncing` or `manual-sync-pending` (see Step 6 footer).
128
128
 
129
- 4d. **OneNote (OPTIONALskip-friendly).** Check `default_onenote_notebook` in `project-evidence.yml`. If it's a placeholder (`<Your Notebook Name>` / `<auto>` / `<skip>` / empty):
129
+ 4d. **OneNote (ENABLED BY DEFAULT kushi v4.8.3+).** OneNote is on by default and gated by a **single switch**: `m365Auth.oneNote.enabled` in `m365-auth.json`. The `project-evidence.yml#default_onenote_notebook` field is now display-only and is NEVER used to gate OneNote (the `<skip>` sentinel is deprecated; existing values are tolerated but ignored).
130
130
 
131
- `ask_user`:
131
+ Check `m365Auth.oneNote.enabled` AND `m365Auth.oneNote.defaultNotebookName`:
132
132
 
133
- > Do you use OneNote on this engagement?
134
- > **Yes and my main notebook is named ___** (recommended if you take meeting notes in OneNote)
135
- > • **No / not yet** — skip OneNote (you can enable later by editing `m365-auth.json` and re-running `@Kushi setup --reconfigure`)
133
+ - `enabled` is missing set `true` (default-on).
134
+ - `defaultNotebookName` is a placeholder (`<Your Notebook Name>` / `<auto>` / empty) prompt only for the notebook name (NOT for enable/disable). `ask_user`:
136
135
 
137
- If **yes**:
138
- - Persist `default_onenote_notebook: "<name>"` to `project-evidence.yml`.
139
- - Persist `m365Auth.oneNote.defaultNotebookName: "<name>"` + `oneNote.enabled: true` to `m365-auth.json`.
140
- - **Do NOT** attempt to auto-resolve a notebook ID via WorkIQ. Per `workiq-onenote-query-shape.instructions.md`, WorkIQ has no notebook-inventory endpoint notebook-ID-lookup and notebook-enumeration queries both route to Graph Explorer instructions (proven 2026-05-26). See the doctrine file's "Forbidden phrasings" table for the exact patterns that fail. The notebook display name is sufficient input for downstream skills; section IDs are resolved per-section at bootstrap-project / refresh time using the natural-language WorkIQ pattern documented in `workiq-onenote-query-shape.instructions.md`.
141
- - Echo: `OneNote enabled. Notebook: "<name>". Section IDs will be discovered at bootstrap-project / refresh time via WorkIQ natural-language queries.`
136
+ > Which OneNote notebook does kushi pull from on this engagement?
137
+ > **Use my default work notebook** — `ISE Work` (recommended for Microsoft consultants)
138
+ > **A different notebook** paste the exact display name
139
+ > **Disable OneNote on this machine**only pick if you genuinely never use OneNote (you can re-enable later by editing `m365-auth.json`)
142
140
 
143
- If **no/skip**:
144
- - Persist `default_onenote_notebook: "<skip>"` to `project-evidence.yml`.
145
- - Set `m365Auth.oneNote.enabled: false` in `m365-auth.json`. Leave all other OneNote fields blank.
146
- - Echo: `OneNote disabled for this contributor. Pull-onenote will report 'not-applicable' in run logs.`
141
+ - Default/different notebook: persist `defaultNotebookName: "<name>"` + ensure `enabled: true`. Do NOT auto-resolve a notebook ID via WorkIQ (per `workiq-onenote-query-shape.instructions.md`).
142
+ - Disable: set `enabled: false`, leave other OneNote fields blank, echo: `OneNote disabled for this contributor. Pull-onenote will report 'not-applicable' in run logs. Re-enable by setting m365Auth.oneNote.enabled: true in m365-auth.json.`
143
+
144
+ - `defaultNotebookName` is already populated AND `enabled: true` silent skip.
145
+ - `enabled: false` (explicitly opted out previously) → silent skip; OneNote stays disabled. `--reconfigure` re-asks.
146
+
147
+ **Single source of truth:** Downstream skills (`pull-onenote`, bootstrap Step 4) gate ONLY on `m365Auth.oneNote.enabled`. Never inspect `default_onenote_notebook` to decide whether to run OneNote.
147
148
 
148
149
  4d-loop. **Microsoft Loop (OPTIONAL — skip-friendly).** Check `default_loop_workspace` in `project-evidence.yml`. If it's a placeholder (`<Your Loop Workspace>` / `<auto>` / `<skip>` / empty):
149
150
 
@@ -16,9 +16,9 @@
16
16
  },
17
17
  "oneNote": {
18
18
  "enabled": true,
19
- "_enabled_note": "Set to false if this contributor does NOT use OneNote on this engagement. When false, pull-onenote becomes a no-op and the OneNote source is reported as not-applicable in run logs.",
20
- "defaultNotebookName": "<Your Notebook Name>",
21
- "_defaultNotebookName_note": "Optional. The OneNote notebook kushi scans by default. Leave as the placeholder to mark OneNote as 'not configured yet' (pull-onenote will skip until set). Run `@Kushi setup` to auto-resolve the notebook ID once you set this.",
19
+ "_enabled_note": "DEFAULT-ON as of kushi v4.8.3. Single source of truth for whether OneNote runs anywhere in kushi. Set to false ONLY when this contributor genuinely does not use OneNote on this engagement; pull-onenote then no-ops and reports the source as `not-applicable` in run logs.",
20
+ "defaultNotebookName": "ISE Work",
21
+ "_defaultNotebookName_note": "Default notebook kushi pulls from. `ISE Work` is the standard Microsoft consultant notebook; override here or via `@Kushi setup` if you use a different one.",
22
22
  "defaultNotebookId": "",
23
23
  "_defaultNotebookId_note": "Optional. Auto-populated by `@Kushi setup` from defaultNotebookName via WorkIQ. Leave blank to defer.",
24
24
  "defaultSectionResolverUrl": "",
@@ -30,11 +30,11 @@ email: <auto>
30
30
  # macOS : '/Users/<you>/OneDrive - <Tenant>/<Team>/Engagement Assets'
31
31
  projects_root: '<engagement-root>'
32
32
 
33
- # OPTIONAL default OneNote notebook to scan for project pages.
34
- # Leave as `<skip>` if you don't use OneNote on this engagement (pull-onenote
35
- # becomes a no-op). Otherwise set to your notebook display name; `@Kushi setup`
36
- # will auto-resolve the notebook ID via WorkIQ and write it to m365-auth.json.
37
- default_onenote_notebook: <Your Notebook Name>
33
+ # DEPRECATED as of v4.8.3 display-only mirror of m365-auth.json#oneNote.defaultNotebookName.
34
+ # Does NOT gate OneNote. The single switch is m365Auth.oneNote.enabled in m365-auth.json
35
+ # (default `true`). To disable OneNote, set that field to false (or pick "Disable OneNote"
36
+ # during `@Kushi setup`). The legacy `<skip>` sentinel is tolerated but ignored.
37
+ default_onenote_notebook: ISE Work
38
38
 
39
39
  # FILL ME IN — projects you actively work on. Kushi scans only these unless
40
40
  # you ask otherwise. Match is fuzzy against subfolder names under projects_root.