kushi-agents 4.4.4 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/package.json +4 -4
- package/plugin/agents/kushi.agent.md +29 -15
- 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/customer-hint-discovery.instructions.md +129 -0
- package/plugin/instructions/email-bootstrap-discovery.instructions.md +105 -0
- 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/meetings-bootstrap-discovery.instructions.md +99 -0
- 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-bootstrap-discovery.instructions.md +97 -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/status-taxonomy.instructions.md +1 -1
- package/plugin/instructions/studio-registry.instructions.md +48 -0
- package/plugin/instructions/teams-bootstrap-discovery.instructions.md +101 -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 +13 -7
- 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 +13 -6
- package/plugin/prompts/bootstrap.prompt.md +9 -7
- package/plugin/prompts/emit-vertex.prompt.md +33 -0
- package/plugin/prompts/setup.prompt.md +1 -1
- 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 +106 -39
- 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 +15 -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 +15 -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 +15 -2
- package/plugin/skills/pull-teams/SKILL.md +15 -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 +289 -86
- 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 +4 -1
- 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 +48 -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 +167 -0
- 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
package/README.md
CHANGED
|
@@ -92,6 +92,8 @@ The Evidence/ folder produced by every profile is a **stable public contract**
|
|
|
92
92
|
| `fde-triage` | standard+ | n/a | 7-file FDE triage bundle at `Reports/triage/<YYYY-MM-DD>/`. File 07 merges across re-runs. |
|
|
93
93
|
| `propose-ado` | **preview** | n/a | Read-only ADO update proposal from latest `_Consolidated/` → `ado-updates/<date>/proposed.md`. Safe to schedule. No ADO writes. |
|
|
94
94
|
| `apply-ado` | **preview** | n/a | Gated apply skill. v0.1.0-preview is dry-mode only (writes `planned.jsonl`); real ADO PATCH/POST lands in v0.1.x. |
|
|
95
|
+
| `vertex-link` | **preview** | n/a | One-time link of a kushi project to a vertex repo `<customer>/<initiative>` (multi-binding supported). Populates `kushi.yaml#vertex`. Re-run with `--reconfigure` to change. |
|
|
96
|
+
| `emit-vertex` | **preview** | n/a | Render vertex-shaped artifacts from kushi Evidence/+State/ — weekly status, decisions, workshops, comms, living-doc diff proposals. Stages first, validates against vertex's own schemas, applies on demand. |
|
|
95
97
|
|
|
96
98
|
See [Quickstart](https://gim-home.github.io/kushi/getting-started/quickstart/) for the full workflow.
|
|
97
99
|
|
|
@@ -151,6 +153,7 @@ Email is stream-only (emails ARE events). Every other source has both. `ask-proj
|
|
|
151
153
|
|---|---|
|
|
152
154
|
| 🚀 [Getting started](https://gim-home.github.io/kushi/getting-started/) | Install + quickstart — pick a target, run one `npx` command |
|
|
153
155
|
| 💡 [Concepts](https://gim-home.github.io/kushi/concepts/) | Hosts, storage backends, snapshot vs stream, multi-user model |
|
|
156
|
+
| 🤝 [Kushi with Vertex](docs/concepts/kushi-with-vertex.md) | Using kushi alongside the [vertex](https://github.com/commercial-software-engineering/vertex) shared note-taking platform — better weekly status, decisions, workshops, and comms |
|
|
154
157
|
| 🛠️ [How-to guides](https://gim-home.github.io/kushi/how-to/) | Schedule refreshes, add contributors, switch backends, upgrade, uninstall |
|
|
155
158
|
| 📖 [Reference](https://gim-home.github.io/kushi/reference/) | Verbs, CLI options, config files, path map, self-check |
|
|
156
159
|
| 📋 [Changelog](CHANGELOG.md) | Release history |
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kushi-agents",
|
|
3
|
-
"version": "4.
|
|
4
|
-
"description": "Install Kushi — multi-source project evidence agent with snapshot+stream capture across Email, Teams, OneNote, SharePoint, Meetings, CRM, ADO. WorkIQ-only for M365 sources (Graph / m365_* FORBIDDEN as fallbacks; user-paste is first-class). Host-agnostic.",
|
|
3
|
+
"version": "4.8.0",
|
|
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": {
|
|
7
7
|
"kushi-agents": "./bin/cli.mjs"
|
|
@@ -41,11 +41,11 @@
|
|
|
41
41
|
},
|
|
42
42
|
"license": "MIT",
|
|
43
43
|
"scripts": {
|
|
44
|
-
"test": "node --test src/check-workiq.test.mjs src/seed-config.test.mjs",
|
|
44
|
+
"test": "node --test src/check-workiq.test.mjs src/seed-config.test.mjs src/sanitize-workiq-input.test.mjs src/detect-vertex-repo.test.mjs src/vertex-validate.test.mjs src/emit-vertex.e2e.test.mjs src/config-root-resolve.test.mjs src/forbidden-workiq-phrasings.test.mjs",
|
|
45
45
|
"smoke": "node scripts/smoke.mjs",
|
|
46
46
|
"prepublishOnly": "npm test && npm run smoke"
|
|
47
47
|
},
|
|
48
48
|
"publishConfig": {
|
|
49
49
|
"access": "public"
|
|
50
50
|
}
|
|
51
|
-
}
|
|
51
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: Kushi
|
|
3
|
-
description: "Kushi — multi-source project evidence + Q&A agent. Snapshot + stream capture across Email, Teams, OneNote, SharePoint, Meetings, CRM, ADO; plus read-only natural-language Q&A over the captured evidence. WorkIQ-first for capture, citation-only for answers. Host-agnostic. USE WHEN the user says any of: PRODUCER VERBS — \"bootstrap a new project\", \"set up project evidence for <X>\", \"add me to project <X>\", \"add contributor to <X>\", \"refresh <X>\", \"do it all for <X>\", \"weekly extract for <X>\", \"regenerate state for <X>\", \"consolidate <X>\", \"status of <X>\"; OR Q&A — the message names a known project (any subfolder under the engagement root) AND asks a question about it (\"what is …\", \"what's the MACC for <X>\", \"who is the EM on <X>\", \"status of <X>\", \"summarize <X>\", \"what was decided about <X>\", \"what's in the deck for <X>\", \"what action items for <X>\", \"<project-name> + <topic>\")."
|
|
3
|
+
description: "Kushi — multi-source project evidence + Q&A agent. Snapshot + stream capture across Email, Teams, OneNote, Loop, SharePoint, Meetings, CRM, ADO; plus read-only natural-language Q&A over the captured evidence. WorkIQ-first for capture, citation-only for answers. Host-agnostic. USE WHEN the user says any of: PRODUCER VERBS — \"bootstrap a new project\", \"set up project evidence for <X>\", \"add me to project <X>\", \"add contributor to <X>\", \"refresh <X>\", \"do it all for <X>\", \"weekly extract for <X>\", \"regenerate state for <X>\", \"consolidate <X>\", \"status of <X>\"; OR Q&A — the message names a known project (any subfolder under the engagement root) AND asks a question about it (\"what is …\", \"what's the MACC for <X>\", \"who is the EM on <X>\", \"status of <X>\", \"summarize <X>\", \"what was decided about <X>\", \"what's in the deck for <X>\", \"what action items for <X>\", \"<project-name> + <topic>\")."
|
|
4
4
|
argument-hint: "Name a project (e.g. 'bootstrap HCA', 'refresh AGCO last 14 days', 'ask HCA what's the MACC?'). Kushi routes to the right verb prompt — never run `npx kushi-agents <verb>` in the terminal."
|
|
5
5
|
tools:
|
|
6
6
|
[vscode/vscodeAPI, execute/getTerminalOutput, execute/runInTerminal, read/readFile, read/terminalSelection, read/terminalLastCommand, agent, edit, search, web, browser, 'workiq/*', 'github/*']
|
|
@@ -8,7 +8,7 @@ tools:
|
|
|
8
8
|
|
|
9
9
|
# @Kushi — Project Evidence Orchestrator
|
|
10
10
|
|
|
11
|
-
Kushi is a multi-source evidence + state agentfor consulting / engineering engagements. It captures **snapshots** (current state of entities) and **streams** (timestamped events) from Email, Teams, OneNote, SharePoint, Meetings, CRM, and ADO, and renders an outcome-based **State** view.
|
|
11
|
+
Kushi is a multi-source evidence + state agentfor consulting / engineering engagements. It captures **snapshots** (current state of entities) and **streams** (timestamped events) from Email, Teams, OneNote, Loop, SharePoint, Meetings, CRM, and ADO, and renders an outcome-based **State** view.
|
|
12
12
|
|
|
13
13
|
## Install profiles
|
|
14
14
|
|
|
@@ -16,7 +16,7 @@ Kushi ships in three profiles. The installed profile is recorded in `kushi-insta
|
|
|
16
16
|
|
|
17
17
|
| Profile | What's installed | Verbs available |
|
|
18
18
|
|---|---|---|
|
|
19
|
-
| `core` | Aggregator only: `setup`, `pull-*`, `consolidate-evidence`, `aggregate-project`, `ask-project`, `project-status`, `self-check`, `intro` | `setup`, `aggregate`, `consolidate`, `status`, `pull`, `ask` |
|
|
19
|
+
| `core` | Aggregator only: `setup`, `pull-*`, `consolidate-evidence`, `aggregate-project`, `ask-project`, `project-status`, `vertex-link`, `emit-vertex`, `self-check`, `intro` | `setup`, `aggregate`, `consolidate`, `status`, `pull`, `ask`, `vertex-link`, `emit-vertex` |
|
|
20
20
|
| `standard` *(default)* | core + `bootstrap-project`, `refresh-project`, `fde-intake`, `fde-report`, `fde-triage` + FDE reference pack | core + `bootstrap`, `refresh`, `fde-intake`, `fde-report`, `fde-triage` |
|
|
21
21
|
| `full` | standard + `build-state` | standard + `state` |
|
|
22
22
|
| **`preview`** *(opt-in)* | standard + `propose-ado-update`, `apply-ado-update` | standard + `propose-ado`, `apply-ado` |
|
|
@@ -29,7 +29,7 @@ The Evidence/ folder produced by `aggregate` is the **public contract** between
|
|
|
29
29
|
|
|
30
30
|
| Verb | Profile | Default window | Calls (in order) |
|
|
31
31
|
|---|---|---|---|
|
|
32
|
-
| `@Kushi setup` | core+ | n/a (read-only) | `setup` — functional WorkIQ ping + identity auto-fill. Idempotent;
|
|
32
|
+
| `@Kushi setup` | core+ | n/a (read-only outbound) | `setup` — auto-EULA + functional WorkIQ ping + identity auto-fill + optional OneNote + multi-folder mailbox config + `projects_root` resolution + file-pointer footer. Idempotent; `--reconfigure` re-walks every question. Required before first bootstrap/refresh. See `instructions/identity-resolution.instructions.md` (v4.4.5 extension). |
|
|
33
33
|
| `@Kushi aggregate <project>` | core+ | since last watermark | `aggregate-project` → `pull-*` (all enabled) → `consolidate-evidence`. **No build-state.** |
|
|
34
34
|
| `@Kushi aggregate <project> last N days` / `since <date>` / `<from>..<to>` | core+ | as supplied | same |
|
|
35
35
|
| `@Kushi bootstrap <project>` | standard+ | last 30 days | `bootstrap-project` → `pull-*` → `consolidate-evidence` → (full only) `build-state` |
|
|
@@ -40,6 +40,8 @@ The Evidence/ folder produced by `aggregate` is the **public contract** between
|
|
|
40
40
|
| `@Kushi status <project>` | core+ | n/a | `project-status` — show run-log |
|
|
41
41
|
| `@Kushi ask <project> <question>` | core+ | n/a (read-only) | `ask-project` — cited Q&A over Evidence/ (+ State/ on full) |
|
|
42
42
|
| `@Kushi pull <source> for <project> [window]` | core+ | as supplied | one `pull-<source>` skill in isolation |
|
|
43
|
+
| `@Kushi vertex-link <project>` | core+ | n/a (one-time mapping) | `vertex-link` — fuzzy-discovers a vertex repo, fuzzy-matches `<customer-slug>/<initiative-slug>/`, writes `kushi.yaml#vertex`. Idempotent; `--reconfigure` re-walks. |
|
|
44
|
+
| `@Kushi emit-vertex <project> [--weekly\|--decisions\|--workshops\|--comms\|--living\|--all]` | core+ | weekly window for `--weekly`, else n/a | `emit-vertex` — renders vertex-shaped artifacts to `<project>/.kushi-staging/vertex/<run-ts>/`, validates via the linked vertex repo's `validate_frontmatter.py`, and (with `--apply`) copies into the vertex repo for GitDoc. Living docs become PR-style diff proposals. |
|
|
43
45
|
| `@Kushi fde-intake <project>` | **standard+** | n/a (read-only) | `fde-intake` — author/update the FDE Intake document at `Reports/00-FDE-Intake-<project>.md` |
|
|
44
46
|
| `@Kushi fde-report <project> [shape]` | **standard+** | n/a (read-only) | `fde-report` — one of 5 shapes: `weekly` (default) / `short` / `long` / `fitness` / `stage-readiness`. Output: `Reports/fde-<shape>-<YYYY-MM-DD>.md` |
|
|
45
47
|
| `@Kushi fde-triage <project>` | **standard+** | n/a (read-only) | `fde-triage` — full 7-file triage bundle at `Reports/triage/<YYYY-MM-DD>/` |
|
|
@@ -65,14 +67,14 @@ See `instructions/snapshot-vs-stream.instructions.md` for the full rule.
|
|
|
65
67
|
|
|
66
68
|
## Core rules (apply to every skill)
|
|
67
69
|
|
|
68
|
-
- **WorkIQ-only** (M365 sources) — `instructions/workiq-only.instructions.md` (supersedes the deprecated `workiq-
|
|
70
|
+
- **WorkIQ-only** (M365 sources) — `instructions/workiq-only.instructions.md` (supersedes the deprecated `workiq-only.instructions.md`). Email/Teams/OneNote/SharePoint/Meetings/Calendar-discovery are WorkIQ-only; Graph REST and `m365_*` host tools are FORBIDDEN as fallbacks. CRM/ADO remain on their direct REST paths.
|
|
69
71
|
- **Canonical evidence layout** (v3.12.1+) — `instructions/evidence-layout-canonical.instructions.md`. Every per-source artifact lives under `<project>/Evidence/<alias>/<source>/{snapshot,stream,...}/`. Sibling source-output folders under `<project>/` (e.g. `<project>/email-context/`, `<project>/notes/`, `<project>/_Weekly Summaries/`) are FORBIDDEN; bootstrap/refresh auto-migrate them into `Evidence/<alias>/<source>/_legacy_*_pre-bootstrap/`.
|
|
70
72
|
- **Scope & Boundaries** — `instructions/scope-boundaries.instructions.md`. Every WorkIQ ask, every `m365_*` call, every CRM/ADO probe MUST cite a boundary from `<engagement-root>/<project>/integrations.yml#boundaries.<source>`. Empty boundary = source disabled (no silent widening).
|
|
71
73
|
- **Evidence Thoroughness Standard** — `instructions/evidence-thoroughness.instructions.md`
|
|
72
74
|
- **Snapshot vs Stream** — `instructions/snapshot-vs-stream.instructions.md`
|
|
73
75
|
- **Side-by-side config** (skeleton + live file always written together) — `instructions/side-by-side-config.instructions.md`
|
|
74
76
|
- **Engagement-root resolution** — `instructions/engagement-root-resolution.instructions.md`
|
|
75
|
-
- **Conditional `az login`** (skip if no CRM/ADO) — `instructions/
|
|
77
|
+
- **Conditional `az login`** (skip if no CRM/ADO) — `instructions/auth-and-retry.instructions.md`
|
|
76
78
|
- **Auth pre-flight, retry, error logging** (mandatory before every external call) — `instructions/auth-and-retry.instructions.md`
|
|
77
79
|
- **Citation Ledger** (every assertion cites source) — `instructions/citation-ledger.instructions.md`
|
|
78
80
|
- **Answer-from-Evidence** (read-only Q&A doctrine for `ask-project`) — `instructions/answer-from-evidence.instructions.md`
|
|
@@ -88,7 +90,7 @@ When a user message arrives:
|
|
|
88
90
|
|
|
89
91
|
1. Identify the **verb** (setup / aggregate / bootstrap / refresh / state / consolidate / status / pull / **ask** / fde-intake / fde-report / fde-triage).
|
|
90
92
|
- If the message starts with an explicit producer verb → use it.
|
|
91
|
-
- **setup** dispatches immediately on `setup`, `verify workiq`, `who am I to kushi`, `fix my install`, `setup kushi`.
|
|
93
|
+
- **setup** dispatches immediately on `setup`, `setup --reconfigure`, `verify workiq`, `who am I to kushi`, `fix my install`, `setup kushi`.
|
|
92
94
|
- Else if the message contains a known project name AND a question shape (interrogative, "status of", "summarize", bare `<project> <topic>`) → `ask`.
|
|
93
95
|
- Else → ask the user to clarify.
|
|
94
96
|
2. **Profile check**: confirm the chosen verb is listed in `kushi-install.json#verbs`. If not, surface: *"Verb `<verb>` requires the `<profile>` profile. Re-install with `npx kushi-agents --clawpilot --profile <profile> --force`."* and stop.
|
|
@@ -103,14 +105,23 @@ When a user message arrives:
|
|
|
103
105
|
|
|
104
106
|
## Configuration layout
|
|
105
107
|
|
|
108
|
+
**Config root** is resolved by `Get-KushiConfig` / `loadKushiConfig`. Two install layouts are first-class (v4.7.2+):
|
|
109
|
+
|
|
110
|
+
| Install command | `<kushi-config-root>` |
|
|
111
|
+
|-----------------------------------------|------------------------------------------|
|
|
112
|
+
| `npx kushi-agents` (vscode, default) | `<workspace>/.kushi/config/` |
|
|
113
|
+
| `npx kushi-agents --clawpilot` | `~/.copilot/m-skills/kushi/config/` |
|
|
114
|
+
|
|
115
|
+
> **Never** treat a missing `<workspace>/.kushi/` as "Kushi isn't installed"
|
|
116
|
+
> and prompt the user to install or overwrite. Always probe via the helper —
|
|
117
|
+
> the Clawpilot install lives outside the workspace. See
|
|
118
|
+
> `instructions/kushi-config-root.instructions.md`.
|
|
119
|
+
|
|
106
120
|
```
|
|
107
|
-
<
|
|
108
|
-
<
|
|
109
|
-
<
|
|
110
|
-
|
|
111
|
-
m365/m365-mutable.json
|
|
112
|
-
crm/config.yml
|
|
113
|
-
ado/config.yml
|
|
121
|
+
<kushi-config-root>/user/project-evidence.yml ← personal: alias, engagement_root, active_projects (seeded by installer; never overwritten)
|
|
122
|
+
<kushi-config-root>/shared/integrations.yml ← optional global CRM/ADO defaults (seeded by installer; never overwritten)
|
|
123
|
+
<kushi-config-root>/user/m365-auth.json ← per-machine, per-user M365 config (v4.4.0+)
|
|
124
|
+
<kushi-config-root>/user/m365-mutable.json
|
|
114
125
|
<engagement-root>/<project>/integrations.yml ← project-shared (all contributors)
|
|
115
126
|
<engagement-root>/<project>/Evidence/contributors.yml
|
|
116
127
|
<engagement-root>/<project>/Evidence/<alias>/.settings.yml ← per-(project × user)
|
|
@@ -143,6 +154,8 @@ Top-level orchestrator skills (called directly by verbs):
|
|
|
143
154
|
| `fde-triage` | **standard+** | Read-only generator of the full 7-file FDE triage bundle. |
|
|
144
155
|
| `propose-ado-update` | **preview** | Read-only generator of `ado-updates/<date>/proposed.md` for an ADO Initiative (FDE Status Summary field + Discussion comment). No ADO writes. Safe to schedule. |
|
|
145
156
|
| `apply-ado-update` | **preview** | Gated apply skill — the only code path authorized to write to ADO. v0.1.0-preview is dry-mode only (writes `planned.jsonl`). Governed by `update-ledger.instructions.md`. |
|
|
157
|
+
| `vertex-link` | core+ | One-time mapping of a kushi project to a vertex repo's `<customer-slug>/<initiative-slug>/`. Writes `kushi.yaml#vertex` with multi-binding support. |
|
|
158
|
+
| `emit-vertex` | core+ | Renders vertex-shaped artifacts (status updates, decisions, workshops, comms; PR-style diffs for living docs) from `Evidence/`+`State/`. Stages then validates against the linked vertex repo's own `validate_frontmatter.py`. `--apply` copies into vertex repo; GitDoc handles commits. |
|
|
146
159
|
|
|
147
160
|
Per-source pull skills (called by `bootstrap-project` / `refresh-project`, or directly via `pull <source>`):
|
|
148
161
|
|
|
@@ -152,8 +165,9 @@ Per-source pull skills (called by `bootstrap-project` / `refresh-project`, or di
|
|
|
152
165
|
| `pull-teams` | Teams chats + channels | ✅ | ✅ |
|
|
153
166
|
| `pull-meetings` | Calendar + transcripts | ✅ | ✅ |
|
|
154
167
|
| `pull-onenote` | OneNote sections | ✅ | ✅ |
|
|
168
|
+
| `pull-loop` | Microsoft Loop workspaces + pages | ✅ | ✅ |
|
|
155
169
|
| `pull-sharepoint` | SharePoint / OneDrive | ✅ | ✅ |
|
|
156
|
-
| `pull-misc` | User-curated `external-links.txt` (
|
|
170
|
+
| `pull-misc` | User-curated `external-links.txt` (web, files, PDFs, GitHub) | ✅ | ✅ |
|
|
157
171
|
| `pull-crm` | Dataverse engagement record | ✅ | ✅ |
|
|
158
172
|
| `pull-ado` | Azure DevOps work items | ✅ | ✅ |
|
|
159
173
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Studio registry for kushi. A 'studio' is an organizational unit that owns distribution lists, report recipients, and other per-org defaults. Borrowed shape from vertex/.vertex/scripts/studios.json (status_email namespace) and extended for kushi (report_recipients, fde_distro, brand).",
|
|
5
|
+
"studios": {
|
|
6
|
+
"_default": {
|
|
7
|
+
"display_name": "Default (no studio)",
|
|
8
|
+
"status_email": {
|
|
9
|
+
"automation_to": "",
|
|
10
|
+
"bcc_recipients": ""
|
|
11
|
+
},
|
|
12
|
+
"report_recipients": {
|
|
13
|
+
"fde_report_to": "",
|
|
14
|
+
"fde_report_cc": ""
|
|
15
|
+
},
|
|
16
|
+
"brand": {
|
|
17
|
+
"name": "",
|
|
18
|
+
"color_hex": ""
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"studio-13": {
|
|
22
|
+
"display_name": "Studio 13",
|
|
23
|
+
"status_email": {
|
|
24
|
+
"automation_to": "\"Status Updates - Studio 13\" <status-updates-studio-13@microsoft.com>",
|
|
25
|
+
"bcc_recipients": "\"Americas Studio 13 LT\" <americas-studio-13-lt@microsoft.com>"
|
|
26
|
+
},
|
|
27
|
+
"report_recipients": {
|
|
28
|
+
"fde_report_to": "",
|
|
29
|
+
"fde_report_cc": ""
|
|
30
|
+
},
|
|
31
|
+
"brand": {
|
|
32
|
+
"name": "Studio 13",
|
|
33
|
+
"color_hex": ""
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "Kushi Studio Registry",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": ["version", "studios"],
|
|
6
|
+
"properties": {
|
|
7
|
+
"version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+$" },
|
|
8
|
+
"description": { "type": "string" },
|
|
9
|
+
"studios": {
|
|
10
|
+
"type": "object",
|
|
11
|
+
"patternProperties": {
|
|
12
|
+
"^[a-z0-9][a-z0-9-]*$|^_default$": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"required": ["display_name"],
|
|
15
|
+
"properties": {
|
|
16
|
+
"display_name": { "type": "string" },
|
|
17
|
+
"status_email": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"properties": {
|
|
20
|
+
"automation_to": { "type": "string" },
|
|
21
|
+
"bcc_recipients": { "type": "string" }
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"report_recipients": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"properties": {
|
|
27
|
+
"fde_report_to": { "type": "string" },
|
|
28
|
+
"fde_report_cc": { "type": "string" }
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"brand": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"properties": {
|
|
34
|
+
"name": { "type": "string" },
|
|
35
|
+
"color_hex": { "type": "string", "pattern": "^(#[0-9a-fA-F]{6})?$" }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"additionalProperties": true
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"additionalProperties": false
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -7,7 +7,7 @@ description: "Auth pre-flight, token reuse, retry, and structured error logging
|
|
|
7
7
|
|
|
8
8
|
Every kushi skill that calls an external service (Graph / m365_*, WorkIQ, Dataverse / CRM, ADO, SharePoint) MUST follow this. Do not skip the pre-flight just because "auth probably works".
|
|
9
9
|
|
|
10
|
-
> **See also:** `
|
|
10
|
+
> **See also:** `auth-and-retry.instructions.md` for concrete PowerShell patterns implementing this doctrine (token acquisition, host-specific SharePoint tokens, ADO tenant validation, `$LASTEXITCODE` discipline, WorkIQ retry code).
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -149,3 +149,270 @@ If a source is partially broken, the run summary table MUST display the status p
|
|
|
149
149
|
| onenote | partial | 0 | Run `workiq accept-eula` once, then re-run `kushi pull onenote <project>` |
|
|
150
150
|
| meetings | partial | 2 | Transcripts not generated for YYYY-MM-DD meetings; reconstructed from chat. To get transcripts on future meetings, enable Teams transcription before joining. |
|
|
151
151
|
```
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
<!-- merged from auth-and-retry.instructions.md (v4.4.9) -->
|
|
155
|
+
## Conditional az login (CRM/ADO only)
|
|
156
|
+
|
|
157
|
+
The skill calls `az account get-access-token` only when CRM (Dataverse) or ADO are configured. WorkIQ does not require `az login`. Most M365-only users will never need to run `az login`.
|
|
158
|
+
|
|
159
|
+
## Decision logic
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
crm_enabled = Test-Path <workspace>/.kushi/config/shared/integrations.yml
|
|
163
|
+
ado_enabled = Test-Path <workspace>/.kushi/config/shared/integrations.yml
|
|
164
|
+
|
|
165
|
+
if (NOT crm_enabled AND NOT ado_enabled):
|
|
166
|
+
Skip az check entirely. Display "az sign-in skipped (no CRM/ADO configured)".
|
|
167
|
+
else:
|
|
168
|
+
Try `az account show` (no browser pop-up).
|
|
169
|
+
If signed-in: continue.
|
|
170
|
+
If NOT signed-in: prompt user with command suggestion (NOT auto-launch):
|
|
171
|
+
"az login --tenant 72f988bf-86f1-41af-91ab-2d7cd011db47"
|
|
172
|
+
After they sign in, re-run.
|
|
173
|
+
If signed-in but token request fails (403, etc.): SOFT WARNING.
|
|
174
|
+
- CRM/ADO sources will be skipped this run.
|
|
175
|
+
- All M365 sources via WorkIQ continue normally.
|
|
176
|
+
- Append a `## Auth Notes` section to the run summary listing what was skipped.
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Tenant ID
|
|
180
|
+
|
|
181
|
+
The Microsoft tenant ID for ADO + CRM JIT auth is `72f988bf-86f1-41af-91ab-2d7cd011db47`. If you suggest `az login`, ALWAYS include `--tenant 72f988bf-86f1-41af-91ab-2d7cd011db47`.
|
|
182
|
+
|
|
183
|
+
## Never block on az failures
|
|
184
|
+
|
|
185
|
+
If `az login` fails or token acquisition fails:
|
|
186
|
+
- Display the error.
|
|
187
|
+
- Mark CRM/ADO sources as `❌ skipped (auth)` in the run summary.
|
|
188
|
+
- CONTINUE the rest of the run. Never abort the whole bootstrap/refresh just because CRM is unreachable.
|
|
189
|
+
|
|
190
|
+
<!-- merged from auth-and-retry.instructions.md (v4.4.9) -->
|
|
191
|
+
## Concrete PowerShell patterns
|
|
192
|
+
|
|
193
|
+
This file is the **concrete** companion to:
|
|
194
|
+
|
|
195
|
+
- `auth-and-retry.instructions.md` — pre-flight, token reuse, retry, error-log schema, path cascade.
|
|
196
|
+
- `auth-and-retry.instructions.md` — when to require `az login` (only if CRM/ADO are configured).
|
|
197
|
+
- `workiq-only.instructions.md` — WorkIQ is the ONLY path for in-scope M365 sources (supersedes the deprecated `workiq-only.instructions.md`).
|
|
198
|
+
|
|
199
|
+
Where those files describe **what** to do, this one shows **how** in PowerShell. Skill authors implementing `pull-crm`, `pull-ado`, `pull-sharepoint`, and any other external-service caller MUST follow the patterns here. Silent 401 loops and "no evidence found" misreports almost always come from skipping one of these.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## 1. Session pre-check (always run first)
|
|
204
|
+
|
|
205
|
+
Before any token acquisition, verify the Azure CLI session and capture the active identity:
|
|
206
|
+
|
|
207
|
+
```powershell
|
|
208
|
+
$accountJson = az account show --output json --only-show-errors 2>&1
|
|
209
|
+
if ($LASTEXITCODE -ne 0) {
|
|
210
|
+
throw "Azure CLI session not found. Run: az login --tenant 72f988bf-86f1-41af-91ab-2d7cd011db47"
|
|
211
|
+
}
|
|
212
|
+
$account = $accountJson | ConvertFrom-Json
|
|
213
|
+
Write-Host "Active tenant: $($account.tenantId) | Account: $($account.user.name)"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Per `az-auth-conditional`: if neither CRM nor ADO is enabled for this engagement, **skip this entire section** and proceed directly to WorkIQ. M365-only users never need `az login`.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## 2. Token acquisition — per service
|
|
221
|
+
|
|
222
|
+
Acquire each token **once per run** (per `auth-and-retry.instructions.md §2`). The tenant ID for Microsoft is `72f988bf-86f1-41af-91ab-2d7cd011db47` — pull it from config when possible, fall back to this literal only for the `az login --tenant` suggestion text.
|
|
223
|
+
|
|
224
|
+
### 2.1 CRM / Dataverse
|
|
225
|
+
|
|
226
|
+
```powershell
|
|
227
|
+
$crmConfig = (Get-Content "$workspace\.kushi\config\shared\integrations.yml" -Raw | ConvertFrom-Yaml).crm # v4.4.0+ — was <engagement-root>\.project-evidence\crm\config.yml
|
|
228
|
+
$tenant = $crmConfig.tenantId
|
|
229
|
+
$crmBaseUrl = $crmConfig.baseUrl
|
|
230
|
+
$crmToken = (az account get-access-token --tenant $tenant --resource $crmBaseUrl --query accessToken -o tsv --only-show-errors 2>&1).Trim()
|
|
231
|
+
if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($crmToken)) {
|
|
232
|
+
throw "Failed to get CRM token (exit $LASTEXITCODE). Run: az login --tenant $tenant"
|
|
233
|
+
}
|
|
234
|
+
$crmHeaders = @{
|
|
235
|
+
Authorization = "Bearer $crmToken"
|
|
236
|
+
Accept = 'application/json'
|
|
237
|
+
'OData-Version' = '4.0'
|
|
238
|
+
'OData-MaxVersion' = '4.0'
|
|
239
|
+
Prefer = 'odata.include-annotations="OData.Community.Display.V1.FormattedValue"'
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### 2.2 Azure DevOps
|
|
244
|
+
|
|
245
|
+
ADO's resource is the constant `499b84ac-1321-427f-aa17-267ca6975798` (Visual Studio Team Services). Read it from config — never hardcode:
|
|
246
|
+
|
|
247
|
+
```powershell
|
|
248
|
+
$adoConfig = (Get-Content "$workspace\.kushi\config\shared\integrations.yml" -Raw | ConvertFrom-Yaml).ado # v4.4.0+ — was <engagement-root>\.project-evidence\ado\config.yml
|
|
249
|
+
$tenant = $adoConfig.tenantId
|
|
250
|
+
$adoRes = $adoConfig.resource # 499b84ac-1321-427f-aa17-267ca6975798
|
|
251
|
+
$adoToken = (az account get-access-token --tenant $tenant --resource $adoRes --query accessToken -o tsv --only-show-errors 2>&1).Trim()
|
|
252
|
+
if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($adoToken)) {
|
|
253
|
+
throw "Failed to get ADO token (exit $LASTEXITCODE). Run: az login --tenant $tenant"
|
|
254
|
+
}
|
|
255
|
+
$adoHeaders = @{ Authorization = "Bearer $adoToken"; Accept = 'application/json'; 'Content-Type' = 'application/json' }
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### 2.3 SharePoint / OneDrive — **host-specific** (critical)
|
|
259
|
+
|
|
260
|
+
SharePoint tokens are bound to a hostname. **Do not assume the configured default host applies to every link.** Personal sites, customer tenants, and `*-df` preview hosts all need their own tokens.
|
|
261
|
+
|
|
262
|
+
Derive the resource from the target URL's origin and acquire the token for that exact host:
|
|
263
|
+
|
|
264
|
+
```powershell
|
|
265
|
+
$targetUrl = '<sharepoint-or-onedrive-url>'
|
|
266
|
+
$targetUri = [Uri]$targetUrl
|
|
267
|
+
$spResource = "$($targetUri.Scheme)://$($targetUri.Host)"
|
|
268
|
+
$spToken = (az account get-access-token --tenant $tenant --resource $spResource --query accessToken -o tsv --only-show-errors 2>&1).Trim()
|
|
269
|
+
if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($spToken)) {
|
|
270
|
+
throw "Failed to get SharePoint token for host $spResource (exit $LASTEXITCODE). Run: az login --tenant $tenant"
|
|
271
|
+
}
|
|
272
|
+
$spHeaders = @{ Authorization = "Bearer $spToken"; Accept = 'application/json' }
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Hosts commonly seen in this workspace: `microsoft-my.sharepoint.com`, `microsoft-my.sharepoint-df.com`, `microsofteur-my.sharepoint.com`, customer tenant `*.sharepoint.com`.
|
|
276
|
+
|
|
277
|
+
#### SharePoint URL traps — browser vs. canonical API
|
|
278
|
+
|
|
279
|
+
A raw browser-facing SharePoint URL is often the **wrong endpoint** for bearer-token retrieval:
|
|
280
|
+
|
|
281
|
+
- `/_layouts/15/Doc.aspx?...`, `?web=1`, and Office share links (`/:x:/`, `/:p:/`, `/:w:/`, `/:b:/`) are browser shells or share URLs — **not** the canonical file-read API.
|
|
282
|
+
- A raw `401` from those URLs does NOT prove Azure CLI auth is broken.
|
|
283
|
+
- **For share links** → prefer Microsoft Graph `shares/{shareId}/driveItem` with `Prefer: redeemSharingLink`.
|
|
284
|
+
- **For direct file paths** under `/personal/.../Documents/...` → prefer SharePoint REST `_api/web/GetFileByServerRelativePath(...)` on the exact host.
|
|
285
|
+
- If the canonical API then returns `403 accessDenied` or SharePoint `UnauthorizedAccessException`, treat it as a **real permission / sharing problem** — do not chase it as a token-host mismatch. Record `errors[]` with `signature: blocked-host-or-permissions-401` per `auth-and-retry.instructions.md §4`.
|
|
286
|
+
|
|
287
|
+
### 2.4 Microsoft Graph / `m365_*` proxies — narrow carve-outs ONLY
|
|
288
|
+
|
|
289
|
+
**Do not use Microsoft Graph or `m365_*` host tools for in-scope M365 sources** (Email / Teams human-readable threads / OneNote bodies / SharePoint content / meeting transcripts / calendar discovery). Per `workiq-only.instructions.md` (v3.11.0+), these are WorkIQ-only. Graph / `m365_*` have a near-100% failure rate in this workspace and pollute the coverage trail.
|
|
290
|
+
|
|
291
|
+
The ONLY allowed Graph / `m365_*` calls inside kushi pull-* skills are:
|
|
292
|
+
|
|
293
|
+
1. **`m365_list_chat_messages(chatId)`** — parallel structured-data dump in `pull-teams` and `pull-meetings`. Writes `chat-messages.json`. Runs in parallel with the WorkIQ human-readable thread pull; NEVER a substitute. If it fails, the WorkIQ artifact still stands and the JSON dump is skipped.
|
|
294
|
+
2. **`m365_download_file(itemId)`** for **binary media only** in `pull-meetings`: `recording.mp4` (when a SharePoint Stream URL is found and size < 200MB) and chat `attachments/<original-name>`. WorkIQ does not return binaries, so this carve-out is required for media survival.
|
|
295
|
+
3. **CRM / ADO** — direct REST via Azure CLI tokens (sections 2.1 and 2.2 of this file). Out of WorkIQ scope.
|
|
296
|
+
|
|
297
|
+
```powershell
|
|
298
|
+
if (-not (Get-Command workiq -ErrorAction SilentlyContinue)) {
|
|
299
|
+
throw "workiq CLI not found on PATH. M365 source queries cannot proceed. See: https://gim-home.github.io/kushi/getting-started/install-workiq/"
|
|
300
|
+
}
|
|
301
|
+
# Prefer the canonical WorkIQ prompts codified in workiq-only.instructions.md.
|
|
302
|
+
# Do NOT improvise. Do NOT fall back to m365_* for in-scope sources.
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
For the allowed carve-outs (`m365_list_chat_messages`, `m365_download_file` for binaries): no `az` token is needed — these go through the Clawpilot M365 proxy authenticated via `m_m365_status` / `m_m365_sign_in`.
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## 3. ADO tenant validation (before any ADO call)
|
|
310
|
+
|
|
311
|
+
Allowed tenants are config-driven, not hardcoded. Validate before the first ADO call:
|
|
312
|
+
|
|
313
|
+
```powershell
|
|
314
|
+
# $account from Section 1
|
|
315
|
+
$adoConfig = (Get-Content "$workspace\.kushi\config\shared\integrations.yml" -Raw | ConvertFrom-Yaml).ado # v4.4.0+
|
|
316
|
+
$allowedTenants = @($adoConfig.allowedTenantIds)
|
|
317
|
+
$currentTenant = $account.tenantId
|
|
318
|
+
if ($allowedTenants.Count -gt 0 -and $allowedTenants -notcontains $currentTenant) {
|
|
319
|
+
throw "Current tenant '$currentTenant' is not allowed for ADO. Allowed: $($allowedTenants -join ', '). Run: az login --tenant $($allowedTenants[0])"
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
If validation fails, record `errors[]` with `signature: ado-tenant-mismatch` and mark the ADO source `❌ skipped (auth)` per `auth-and-retry §4` — do not abort the whole run.
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## 4. Mandatory $LASTEXITCODE pattern
|
|
328
|
+
|
|
329
|
+
Check `$LASTEXITCODE` immediately after every `az` invocation. Never proceed with a null or empty result. Always pipe `2>&1` so stderr is captured into error messages, and use `--only-show-errors` on token calls to keep informational banners out of the token value:
|
|
330
|
+
|
|
331
|
+
```powershell
|
|
332
|
+
$result = az <command> --output json --only-show-errors 2>&1
|
|
333
|
+
if ($LASTEXITCODE -ne 0) {
|
|
334
|
+
throw "az command failed (exit $LASTEXITCODE): $result"
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## 5. WorkIQ availability + retry (concrete)
|
|
341
|
+
|
|
342
|
+
Per `workiq-only.instructions.md` and `auth-and-retry.instructions.md §3`. Before the first WorkIQ call per run:
|
|
343
|
+
|
|
344
|
+
```powershell
|
|
345
|
+
if (-not (Get-Command workiq -ErrorAction SilentlyContinue)) {
|
|
346
|
+
throw "workiq CLI not found on PATH. WorkIQ queries cannot proceed. See install-workiq.md."
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Retry loop (transient errors only — throttling is NOT a retry case):
|
|
351
|
+
|
|
352
|
+
```powershell
|
|
353
|
+
$maxRetries = 2
|
|
354
|
+
$attempt = 0
|
|
355
|
+
$output = $null
|
|
356
|
+
do {
|
|
357
|
+
$attempt++
|
|
358
|
+
$output = (workiq ask -q $query 2>&1 | Out-String).Trim()
|
|
359
|
+
$isTransient = ($LASTEXITCODE -ne 0) -or ($output -match '^(Error:\s+Unexpected error|Server error)')
|
|
360
|
+
$isThrottled = ($output -match 'tooManyRequests|More than 3 retries performed|high demand')
|
|
361
|
+
if ($isThrottled) {
|
|
362
|
+
# Do NOT retry the same query. Narrow once if possible, else record and continue.
|
|
363
|
+
throw "WorkIQ throttled — record 'throttled-tooManyRequests' and move on per auth-and-retry §3."
|
|
364
|
+
}
|
|
365
|
+
if (-not $isTransient) { break }
|
|
366
|
+
if ($attempt -gt $maxRetries) {
|
|
367
|
+
throw "WorkIQ failed after $attempt attempt(s): $output"
|
|
368
|
+
}
|
|
369
|
+
Start-Sleep -Seconds (3 * $attempt)
|
|
370
|
+
} while ($true)
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## 6. Token reuse + mid-run 401 recovery
|
|
376
|
+
|
|
377
|
+
Per `auth-and-retry §2`: acquire each token once, reuse it. On HTTP 401 mid-run, **re-acquire once** and retry the failed call. If still 401, record `errors[]` with `signature: token-401-after-reacquire` and stop calling that service.
|
|
378
|
+
|
|
379
|
+
```powershell
|
|
380
|
+
# Mid-run 401 — re-acquire then retry once
|
|
381
|
+
$crmToken = (az account get-access-token --tenant $tenant --resource $crmBaseUrl --query accessToken -o tsv --only-show-errors 2>&1).Trim()
|
|
382
|
+
$crmHeaders.Authorization = "Bearer $crmToken"
|
|
383
|
+
# retry the failed call ONCE
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## 7. Failure signature reference
|
|
389
|
+
|
|
390
|
+
Maintained alongside `auth-and-retry §3` (canonical) — quick lookup:
|
|
391
|
+
|
|
392
|
+
| Symptom | Likely cause | Recovery |
|
|
393
|
+
|---------|--------------|----------|
|
|
394
|
+
| `az account show` non-zero | Not logged in | `az login --tenant 72f988bf-86f1-41af-91ab-2d7cd011db47` |
|
|
395
|
+
| Token empty / whitespace | Expired session or parse issue | Re-login, re-acquire |
|
|
396
|
+
| HTTP 401 on API call | Token expired mid-run | Re-acquire once (§6), retry once |
|
|
397
|
+
| HTTP 401 on SharePoint URL | Token for wrong host | Re-acquire for exact URL origin (§2.3); if still 401, record `blocked-host-or-permissions-401` |
|
|
398
|
+
| Browser SP URL 401, but Graph shares / SP REST 403 | Wrong retrieval surface; canonical API exposed real permission failure | Stop retrying browser URL; classify as share/permission problem |
|
|
399
|
+
| OneNote via Graph 401/40001 | Wrong path | Switch to WorkIQ, narrowest query first (`one_sectionFileId`) |
|
|
400
|
+
| ADO tenant mismatch | Wrong-tenant session | `az login --tenant <allowed>` (§3) |
|
|
401
|
+
| Dataverse 400 OData | Invalid field / filter | Revert to known-good query; add filters one at a time |
|
|
402
|
+
| WorkIQ exits non-zero (transient) | Server hiccup | Retry pattern (§5), max 2 retries |
|
|
403
|
+
| WorkIQ `tooManyRequests` | Throttling | Narrow scope once; else record `throttled-tooManyRequests` and stop |
|
|
404
|
+
| WorkIQ "Sorry, I can't" | Blocked/copyright | Record `skipped-blocked`, continue |
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## 8. Config source of truth
|
|
409
|
+
|
|
410
|
+
| Service | Config file (engagement-scoped) |
|
|
411
|
+
|---------|---------------------------------|
|
|
412
|
+
| Dynamics 365 / CRM | `<workspace>/.kushi/config/shared/integrations.yml` |
|
|
413
|
+
| Azure DevOps | `<workspace>/.kushi/config/shared/integrations.yml` |
|
|
414
|
+
| Microsoft Graph / M365 / OneNote | `<workspace>/.kushi/config/user/m365-mutable.json` + `<workspace>/.kushi/config/user/m365-auth.json` |
|
|
415
|
+
| WorkIQ CLI path | `<workspace>/.kushi/config/user/project-evidence.yml` (workspace-scoped) |
|
|
416
|
+
| Global integrations (optional) | `<workspace>/.kushi/config/shared/integrations.yml` |
|
|
417
|
+
|
|
418
|
+
Always read tenant IDs, resource URLs, org URLs, and allowed-tenant lists from these files at the start of each run. **Never hardcode them in skills or prompts.** The only acceptable literal in instructions/prompts is the public Microsoft tenant ID `72f988bf-86f1-41af-91ab-2d7cd011db47` in the user-facing `az login --tenant ...` suggestion text.
|