crewly 1.8.4 → 1.8.5
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/config/roles/_common/wiki-instructions.md +33 -0
- package/config/roles/orchestrator/prompt.md +35 -0
- package/config/roles/team-leader/prompt.md +38 -0
- package/config/skills/agent/core/wiki-query/SKILL.md +66 -0
- package/config/skills/agent/core/wiki-query/execute.sh +107 -0
- package/config/skills/orchestrator/wiki-bookkeep/SKILL.md +71 -0
- package/config/skills/orchestrator/wiki-bookkeep/execute.sh +72 -0
- package/config/skills/orchestrator/wiki-ingest/SKILL.md +63 -0
- package/config/skills/orchestrator/wiki-ingest/execute.sh +113 -0
- package/config/skills/orchestrator/wiki-process-queue/SKILL.md +71 -0
- package/config/skills/orchestrator/wiki-process-queue/execute.sh +93 -0
- package/config/skills/orchestrator/wiki-queue-add/SKILL.md +89 -0
- package/config/skills/orchestrator/wiki-queue-add/execute.sh +115 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.d.ts +134 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.js +718 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.routes.d.ts +23 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.routes.js +43 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.routes.js.map +1 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +39 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +4 -0
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session.d.ts +28 -0
- package/dist/backend/backend/src/services/session/pty/pty-session.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session.js +162 -4
- package/dist/backend/backend/src/services/session/pty/pty-session.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/referenced-by.resolver.d.ts +69 -0
- package/dist/backend/backend/src/services/wiki/referenced-by.resolver.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/referenced-by.resolver.js +174 -0
- package/dist/backend/backend/src/services/wiki/referenced-by.resolver.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/schema-loader.service.d.ts +57 -0
- package/dist/backend/backend/src/services/wiki/schema-loader.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/schema-loader.service.js +183 -0
- package/dist/backend/backend/src/services/wiki/schema-loader.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.d.ts +86 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.js +187 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.d.ts +116 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.js +299 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.d.ts +74 -0
- package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.js +154 -0
- package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.d.ts +100 -0
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.js +212 -0
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-process.service.d.ts +84 -0
- package/dist/backend/backend/src/services/wiki/wiki-process.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-process.service.js +138 -0
- package/dist/backend/backend/src/services/wiki/wiki-process.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts +115 -0
- package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-query.service.js +291 -0
- package/dist/backend/backend/src/services/wiki/wiki-query.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-queue.service.d.ts +115 -0
- package/dist/backend/backend/src/services/wiki/wiki-queue.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-queue.service.js +261 -0
- package/dist/backend/backend/src/services/wiki/wiki-queue.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki.types.d.ts +84 -0
- package/dist/backend/backend/src/services/wiki/wiki.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki.types.js +10 -0
- package/dist/backend/backend/src/services/wiki/wiki.types.js.map +1 -0
- package/frontend/dist/assets/{index-b279da34.js → index-cc115bb4.js} +246 -246
- package/frontend/dist/assets/{index-c07e04c0.css → index-db3f5041.css} +1 -1
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Wiki Process Queue
|
|
3
|
+
description: Claim the next pending wiki-queue item and get the vault context your LLM needs to classify it into llm-curated/<folder>/<page>.md. No preset taxonomy — your LLM picks the target.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
category: knowledge
|
|
6
|
+
skillType: claude-skill
|
|
7
|
+
assignableRoles:
|
|
8
|
+
- orchestrator
|
|
9
|
+
- team-leader
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Wiki Process Queue
|
|
13
|
+
|
|
14
|
+
Claim the next pending queue item and get back the vault state your runtime's LLM should classify against. **This skill does not call an LLM.** It returns the structured context; your runtime concatenates with the per-LLM task-instruction prompt and synthesizes a target page.
|
|
15
|
+
|
|
16
|
+
## After this skill returns, YOUR runtime MUST:
|
|
17
|
+
|
|
18
|
+
1. Read `result.item.content` + `result.item.reason` (the agent who queued it justified why).
|
|
19
|
+
2. Read `result.vaultContext` (SCHEMA, frozen paths, recent log, candidate pages).
|
|
20
|
+
3. Use your LLM to pick a target. Options:
|
|
21
|
+
- **Merge** into an existing `result.vaultContext.candidatePages[i].path` — preferred if a candidate fits.
|
|
22
|
+
- **Create** a new page under `llm-curated/<freshly-invented-subfolder>/<slug>.md`. You may invent subfolder names; there is NO preset taxonomy.
|
|
23
|
+
- **Skip** if you decide the item isn't wiki-worthy after all.
|
|
24
|
+
4. Commit:
|
|
25
|
+
- To write: call `wiki-ingest` with `--vault`, `--source-type`, `--source-ref`, `--source-body`, and `--target <relative-path>`.
|
|
26
|
+
- Then POST `/api/wiki/queue/<id>/process` with `{ingested:true, pagesWritten:[…], targetPath:'…', summary:'…'}`.
|
|
27
|
+
- To skip: POST `/api/wiki/queue/<id>/skip` with `{skipReason:'…'}`.
|
|
28
|
+
|
|
29
|
+
## Hard rules your LLM must honor
|
|
30
|
+
|
|
31
|
+
- **NEVER target a frozen folder** (`result.vaultContext.schemaSummary.frozenPaths`). The ingest call will reject these with HTTP 422.
|
|
32
|
+
- **PREFER merging into an existing page** over creating a new one. Only create new when nothing fits.
|
|
33
|
+
- **DO NOT re-justify wiki-worthiness** — the agent who queued the item already did (`result.item.reason`). Your job is classification, not gatekeeping. The exception is skip: if context reveals the item is a duplicate / low signal, skip with a `skipReason`.
|
|
34
|
+
|
|
35
|
+
## Inputs
|
|
36
|
+
|
|
37
|
+
| Flag | Required | Description |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| `--claimed-by <session>` | yes | Your agent session name. Defaults to `$CREWLY_SESSION_NAME` or `crewly-orc`. |
|
|
40
|
+
| `--vault <path>` | no | Filter to a specific vault. Default: any vault with pending items. |
|
|
41
|
+
| `--offset <n>` | no | Skip the first N pending items. Useful for retry after a skip. |
|
|
42
|
+
| `--top-k <n>` | no | How many candidate pages to surface (default 5). |
|
|
43
|
+
| `--recent-log <n>` | no | How many tail log entries to include (default 10). |
|
|
44
|
+
|
|
45
|
+
## Output
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"success": true,
|
|
50
|
+
"result": {
|
|
51
|
+
"item": { "id": "uuid", "content": "...", "reason": "...", "status": "claimed", ... },
|
|
52
|
+
"vaultContext": {
|
|
53
|
+
"vault": { "scope": "project", "id": "crewly", "path": "..." },
|
|
54
|
+
"schemaSummary": { "hardcoded": [...], "llmCurated": [...], "frozenPaths": ["memory/", "sop-overrides/"], "writePolicy": {...} },
|
|
55
|
+
"recentLog": [...],
|
|
56
|
+
"candidatePages": [{"path": "llm-curated/customers/anthropic.md", "score": 9, "excerpt": "..."}],
|
|
57
|
+
"callerNotes": ["Cite pages by path.", "Refuse writes into frozenPaths.", ...]
|
|
58
|
+
},
|
|
59
|
+
"classifierNotes": [
|
|
60
|
+
"You have ALREADY decided this item is wiki-worthy at queue-add time...",
|
|
61
|
+
"Pick the target page path under llm-curated/...",
|
|
62
|
+
...
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Failure modes
|
|
69
|
+
|
|
70
|
+
- `404 no_pending_items` — queue is empty (for the filter you provided). Not an error; nothing to do this turn.
|
|
71
|
+
- `400 claimedBy is required` — every claim is owned by a session for audit.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# wiki-process-queue — claim the next pending wiki item + return the
|
|
3
|
+
# system-context your runtime should classify it against.
|
|
4
|
+
#
|
|
5
|
+
# This skill does NOT call an LLM. It returns the queue item + the
|
|
6
|
+
# vault's current state (SCHEMA, frozen paths, recent log, candidate
|
|
7
|
+
# pages by keyword overlap). Your runtime concatenates with the per-LLM
|
|
8
|
+
# task-instruction prompt at prompts/<runtime>.md and synthesizes a
|
|
9
|
+
# target path. After the LLM picks a target you (the agent) MUST:
|
|
10
|
+
#
|
|
11
|
+
# 1. POST /api/wiki/ingest with { vaultPath, targetRelativePath, ... }
|
|
12
|
+
# 2. POST /api/wiki/queue/<id>/process with { ingested, pagesWritten,
|
|
13
|
+
# targetPath, summary }
|
|
14
|
+
# …OR…
|
|
15
|
+
# 3. POST /api/wiki/queue/<id>/skip with { skipReason } if you decided
|
|
16
|
+
# the item isn't actually wiki-worthy after seeing the vault context.
|
|
17
|
+
#
|
|
18
|
+
# Usage:
|
|
19
|
+
# bash execute.sh --claimed-by <session>
|
|
20
|
+
# bash execute.sh --claimed-by <session> --vault /path --top-k 5
|
|
21
|
+
# bash execute.sh --json '{"claimedBy":"crewly-orc","vaultPath":"/path"}'
|
|
22
|
+
set -euo pipefail
|
|
23
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
24
|
+
source "${SCRIPT_DIR}/../../_common/lib.sh"
|
|
25
|
+
|
|
26
|
+
INPUT_JSON=""
|
|
27
|
+
CLAIMED_BY=""
|
|
28
|
+
VAULT_PATH=""
|
|
29
|
+
OFFSET=""
|
|
30
|
+
TOP_K=""
|
|
31
|
+
RECENT_LOG=""
|
|
32
|
+
|
|
33
|
+
if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
|
|
34
|
+
INPUT_JSON="$1"
|
|
35
|
+
shift || true
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
while [[ $# -gt 0 ]]; do
|
|
39
|
+
case "$1" in
|
|
40
|
+
--claimed-by|-b) CLAIMED_BY="$2"; shift 2 ;;
|
|
41
|
+
--vault|-v) VAULT_PATH="$2"; shift 2 ;;
|
|
42
|
+
--offset|-o) OFFSET="$2"; shift 2 ;;
|
|
43
|
+
--top-k|-k) TOP_K="$2"; shift 2 ;;
|
|
44
|
+
--recent-log|-r) RECENT_LOG="$2"; shift 2 ;;
|
|
45
|
+
--json|-j) INPUT_JSON="$2"; shift 2 ;;
|
|
46
|
+
--help|-h)
|
|
47
|
+
cat <<EOF
|
|
48
|
+
Usage:
|
|
49
|
+
execute.sh --claimed-by <session> [--vault <path>] [--offset N] [--top-k 5] [--recent-log 10]
|
|
50
|
+
execute.sh --json '{"claimedBy":"crewly-orc","vaultPath":"...","offset":0}'
|
|
51
|
+
|
|
52
|
+
Claims the next pending queue item AND returns the vault context for
|
|
53
|
+
your runtime's LLM to classify. After the LLM picks a target, call:
|
|
54
|
+
- /api/wiki/ingest (write the page)
|
|
55
|
+
- /api/wiki/queue/<id>/process (mark this item processed)
|
|
56
|
+
…or:
|
|
57
|
+
- /api/wiki/queue/<id>/skip (mark not-wiki-worthy after all)
|
|
58
|
+
EOF
|
|
59
|
+
exit 0 ;;
|
|
60
|
+
--) shift; break ;;
|
|
61
|
+
*)
|
|
62
|
+
if [[ -z "$INPUT_JSON" && ${1:0:1} == '{' ]]; then INPUT_JSON="$1"; shift
|
|
63
|
+
else error_exit "Unknown argument: $1"; fi ;;
|
|
64
|
+
esac
|
|
65
|
+
done
|
|
66
|
+
|
|
67
|
+
if [ -z "$INPUT_JSON" ] && [ -z "$CLAIMED_BY" ] && [ ! -t 0 ]; then
|
|
68
|
+
STDIN_DATA="$(cat)"
|
|
69
|
+
if [[ ${STDIN_DATA:0:1} == '{' ]]; then INPUT_JSON="$STDIN_DATA"; fi
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
if [ -n "$INPUT_JSON" ]; then
|
|
73
|
+
INPUT=$(read_json_input "$INPUT_JSON")
|
|
74
|
+
[ -z "$CLAIMED_BY" ] && CLAIMED_BY=$(printf '%s' "$INPUT" | jq -r '.claimedBy // empty')
|
|
75
|
+
[ -z "$VAULT_PATH" ] && VAULT_PATH=$(printf '%s' "$INPUT" | jq -r '.vaultPath // empty')
|
|
76
|
+
[ -z "$OFFSET" ] && OFFSET=$(printf '%s' "$INPUT" | jq -r '.offset // empty')
|
|
77
|
+
[ -z "$TOP_K" ] && TOP_K=$(printf '%s' "$INPUT" | jq -r '.topK // empty')
|
|
78
|
+
[ -z "$RECENT_LOG" ] && RECENT_LOG=$(printf '%s' "$INPUT" | jq -r '.recentLogEntries // empty')
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
if [ -z "$CLAIMED_BY" ]; then
|
|
82
|
+
CLAIMED_BY="${CREWLY_SESSION_NAME:-crewly-orc}"
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
export _WPQ_BY="$CLAIMED_BY"
|
|
86
|
+
BODY=$(jq -n '{claimedBy: env._WPQ_BY}')
|
|
87
|
+
[ -n "$VAULT_PATH" ] && { export _WPQ_V="$VAULT_PATH"; BODY=$(echo "$BODY" | jq '. + {vaultPath: env._WPQ_V}'); unset _WPQ_V; }
|
|
88
|
+
[ -n "$OFFSET" ] && BODY=$(echo "$BODY" | jq --argjson o "$OFFSET" '. + {offset: $o}')
|
|
89
|
+
[ -n "$TOP_K" ] && BODY=$(echo "$BODY" | jq --argjson k "$TOP_K" '. + {topK: $k}')
|
|
90
|
+
[ -n "$RECENT_LOG" ] && BODY=$(echo "$BODY" | jq --argjson n "$RECENT_LOG" '. + {recentLogEntries: $n}')
|
|
91
|
+
unset _WPQ_BY
|
|
92
|
+
|
|
93
|
+
api_call POST "/wiki/queue/claim-next" "$BODY"
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Wiki Queue Add
|
|
3
|
+
description: Enqueue wiki-worthy content (from a chat turn, spec write, PR merge, learning) for later agent-driven classification + ingest. Agents must justify with --reason.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
category: knowledge
|
|
6
|
+
skillType: claude-skill
|
|
7
|
+
assignableRoles:
|
|
8
|
+
- orchestrator
|
|
9
|
+
- team-leader
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Wiki Queue Add
|
|
13
|
+
|
|
14
|
+
Enqueue a candidate item for the LLM-wiki. This skill **does not write** to the vault — it adds the item to a queue. A separate `wiki-process-queue` run (later, batch or bookkeep-triggered) decides whether the item is actually worth saving and where in the vault it lands.
|
|
15
|
+
|
|
16
|
+
## When to use
|
|
17
|
+
|
|
18
|
+
After a chat turn (yours OR a teammate's), pause briefly and ask:
|
|
19
|
+
|
|
20
|
+
- Did this turn produce content with **lasting value**?
|
|
21
|
+
- a decision (pricing, scope, scheduling)
|
|
22
|
+
- a fact about a person, customer, partner
|
|
23
|
+
- a pattern that future-me would want to find
|
|
24
|
+
- a new constraint, gotcha, or learning
|
|
25
|
+
- Was a fact mentioned that the team will need to look up later?
|
|
26
|
+
|
|
27
|
+
If YES, call `wiki-queue-add`. **DO NOT call it for**:
|
|
28
|
+
|
|
29
|
+
- Routine status checks ("standup", "?", "ok")
|
|
30
|
+
- Implementation details captured in code/PRs
|
|
31
|
+
- Conversation pleasantries
|
|
32
|
+
- Anything already in the wiki
|
|
33
|
+
|
|
34
|
+
## Required arguments
|
|
35
|
+
|
|
36
|
+
| Flag | Required | Purpose |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `--vault <path>` | yes | Absolute path to the vault root. |
|
|
39
|
+
| `--content <text>` | yes | The text to capture. |
|
|
40
|
+
| `--reason <text>` | **yes** | One sentence: WHY is this wiki-worthy? Audit + helps the processor decide where it goes. |
|
|
41
|
+
| `--source-ref <ref>` | yes | Stable reference: chat msg id, slack thread, file path, WI id. |
|
|
42
|
+
| `--source-type <type>` | no | Default `user_chat`. Use `slack_message`, `spec_file`, `pr_merge`, `record_learning`, `task_verified` when appropriate. |
|
|
43
|
+
| `--queued-by <sess>` | no | Defaults to `$CREWLY_SESSION_NAME` or `crewly-orc`. |
|
|
44
|
+
|
|
45
|
+
## Examples
|
|
46
|
+
|
|
47
|
+
**A pricing decision the team should remember:**
|
|
48
|
+
```bash
|
|
49
|
+
bash execute.sh \
|
|
50
|
+
--vault ~/Desktop/projects/crewly-projects/crewly/.crewly/wiki \
|
|
51
|
+
--content "Anthropic SMB pilot signed at \$799/month, 12-month commit, 30-day onboarding clause" \
|
|
52
|
+
--reason "first paid SMB customer + concrete pricing validation point + new contract pattern" \
|
|
53
|
+
--source-ref "slack://D0AC7NF5N7L/1779509999.111"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**A learning a worker just surfaced:**
|
|
57
|
+
```bash
|
|
58
|
+
bash execute.sh \
|
|
59
|
+
--vault ~/.crewly/teams/ad923b66-…/wiki \
|
|
60
|
+
--content "Gemini text-embedding-004 returned 404 — deprecated. Falling back to keyword search." \
|
|
61
|
+
--reason "infra gotcha — affects every team using vector search; future-me will hit this" \
|
|
62
|
+
--source-ref "wi:6cf2d54d-…" \
|
|
63
|
+
--source-type record_learning
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Output
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"success": true,
|
|
71
|
+
"item": {
|
|
72
|
+
"id": "uuid",
|
|
73
|
+
"status": "pending",
|
|
74
|
+
"queuedAt": "2026-05-22T...",
|
|
75
|
+
"vaultPath": "...",
|
|
76
|
+
"content": "...",
|
|
77
|
+
"reason": "...",
|
|
78
|
+
...
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The item sits in the queue until processed. Use `wiki-queue-list` to see pending items and `wiki-process-queue` to claim + classify + ingest.
|
|
84
|
+
|
|
85
|
+
## Failure modes
|
|
86
|
+
|
|
87
|
+
- `400 reason is required` — agents MUST justify wiki-worthiness; refusal protects future-me from low-signal noise
|
|
88
|
+
- `400 content/sourceRef empty` — every queued item needs identifiable provenance
|
|
89
|
+
- `400 vaultPath must be absolute` — relative paths are rejected; the vault root is part of the audit trail
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# wiki-queue-add — enqueue wiki-worthy content the agent just saw or said.
|
|
3
|
+
#
|
|
4
|
+
# Per the 2026-05-22 redesign (Steve): there's NO automatic ingest. Agents
|
|
5
|
+
# decide what's worth saving as the conversation unfolds and queue it
|
|
6
|
+
# explicitly. A separate `wiki-process-queue` skill (run later, batch or
|
|
7
|
+
# bookkeep-triggered) classifies + writes to llm-curated/<folder>/<page>.md.
|
|
8
|
+
#
|
|
9
|
+
# The `--reason` is REQUIRED — agents must justify why this is wiki-worthy.
|
|
10
|
+
#
|
|
11
|
+
# Usage:
|
|
12
|
+
# bash execute.sh --vault /path --content "..." --reason "..." --source-ref "..."
|
|
13
|
+
# bash execute.sh --json '{"vaultPath":"...","content":"...","reason":"...","sourceRef":"...","sourceType":"user_chat"}'
|
|
14
|
+
set -euo pipefail
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
|
+
source "${SCRIPT_DIR}/../../_common/lib.sh"
|
|
17
|
+
|
|
18
|
+
INPUT_JSON=""
|
|
19
|
+
VAULT_PATH=""
|
|
20
|
+
CONTENT=""
|
|
21
|
+
REASON=""
|
|
22
|
+
SOURCE_REF=""
|
|
23
|
+
SOURCE_TYPE="user_chat"
|
|
24
|
+
QUEUED_BY=""
|
|
25
|
+
|
|
26
|
+
# Legacy positional JSON
|
|
27
|
+
if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
|
|
28
|
+
INPUT_JSON="$1"
|
|
29
|
+
shift || true
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
while [[ $# -gt 0 ]]; do
|
|
33
|
+
case "$1" in
|
|
34
|
+
--vault|-v) VAULT_PATH="$2"; shift 2 ;;
|
|
35
|
+
--content|-c) CONTENT="$2"; shift 2 ;;
|
|
36
|
+
--reason|-r) REASON="$2"; shift 2 ;;
|
|
37
|
+
--source-ref) SOURCE_REF="$2"; shift 2 ;;
|
|
38
|
+
--source-type) SOURCE_TYPE="$2"; shift 2 ;;
|
|
39
|
+
--queued-by) QUEUED_BY="$2"; shift 2 ;;
|
|
40
|
+
--json|-j) INPUT_JSON="$2"; shift 2 ;;
|
|
41
|
+
--help|-h)
|
|
42
|
+
cat <<EOF
|
|
43
|
+
Usage:
|
|
44
|
+
execute.sh --vault <vault> --content "<text>" --reason "<why this matters>" --source-ref "<id|url|path>" [--source-type user_chat|slack_message|spec_file|pr_merge|record_learning|task_verified] [--queued-by <session>]
|
|
45
|
+
|
|
46
|
+
Required:
|
|
47
|
+
--vault Absolute path to the vault root.
|
|
48
|
+
--content The text to capture (the thing future-you wants to remember).
|
|
49
|
+
--reason WHY this is wiki-worthy. One sentence. Audit + helps the processor.
|
|
50
|
+
--source-ref Stable reference: chat id, slack thread, file path, WI id.
|
|
51
|
+
|
|
52
|
+
Optional:
|
|
53
|
+
--source-type Default: user_chat. Use slack_message for Slack inbound; spec_file
|
|
54
|
+
for written specs; pr_merge for commit-driven learnings; etc.
|
|
55
|
+
--queued-by Session name. Defaults to \$CREWLY_SESSION_NAME or "crewly-orc".
|
|
56
|
+
|
|
57
|
+
Emit a JSON {success, item} on stdout. The item has status=pending until a
|
|
58
|
+
later wiki-process-queue run classifies it.
|
|
59
|
+
EOF
|
|
60
|
+
exit 0 ;;
|
|
61
|
+
--) shift; break ;;
|
|
62
|
+
*)
|
|
63
|
+
if [[ -z "$INPUT_JSON" && ${1:0:1} == '{' ]]; then INPUT_JSON="$1"; shift
|
|
64
|
+
else error_exit "Unknown argument: $1"; fi ;;
|
|
65
|
+
esac
|
|
66
|
+
done
|
|
67
|
+
|
|
68
|
+
# stdin JSON fallback
|
|
69
|
+
if [ -z "$INPUT_JSON" ] && [ -z "$CONTENT" ] && [ ! -t 0 ]; then
|
|
70
|
+
STDIN_DATA="$(cat)"
|
|
71
|
+
if [[ ${STDIN_DATA:0:1} == '{' ]]; then INPUT_JSON="$STDIN_DATA"
|
|
72
|
+
else CONTENT="$STDIN_DATA"; fi
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
if [ -n "$INPUT_JSON" ]; then
|
|
76
|
+
INPUT=$(read_json_input "$INPUT_JSON")
|
|
77
|
+
[ -z "$VAULT_PATH" ] && VAULT_PATH=$(printf '%s' "$INPUT" | jq -r '.vaultPath // empty')
|
|
78
|
+
[ -z "$CONTENT" ] && CONTENT=$(printf '%s' "$INPUT" | jq -r '.content // empty')
|
|
79
|
+
[ -z "$REASON" ] && REASON=$(printf '%s' "$INPUT" | jq -r '.reason // empty')
|
|
80
|
+
[ -z "$SOURCE_REF" ] && SOURCE_REF=$(printf '%s' "$INPUT" | jq -r '.sourceRef // empty')
|
|
81
|
+
[ "$SOURCE_TYPE" = "user_chat" ] && {
|
|
82
|
+
TY=$(printf '%s' "$INPUT" | jq -r '.sourceType // empty'); [ -n "$TY" ] && SOURCE_TYPE="$TY"
|
|
83
|
+
}
|
|
84
|
+
[ -z "$QUEUED_BY" ] && QUEUED_BY=$(printf '%s' "$INPUT" | jq -r '.queuedBy // empty')
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
require_param "vaultPath (--vault)" "$VAULT_PATH"
|
|
88
|
+
require_param "content (--content)" "$CONTENT"
|
|
89
|
+
require_param "reason (--reason)" "$REASON"
|
|
90
|
+
require_param "sourceRef (--source-ref)" "$SOURCE_REF"
|
|
91
|
+
|
|
92
|
+
# Default queuedBy: session name from env, else "crewly-orc"
|
|
93
|
+
if [ -z "$QUEUED_BY" ]; then
|
|
94
|
+
QUEUED_BY="${CREWLY_SESSION_NAME:-crewly-orc}"
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
export _WQA_VAULT="$VAULT_PATH"
|
|
98
|
+
export _WQA_CONTENT="$CONTENT"
|
|
99
|
+
export _WQA_REASON="$REASON"
|
|
100
|
+
export _WQA_REF="$SOURCE_REF"
|
|
101
|
+
export _WQA_TYPE="$SOURCE_TYPE"
|
|
102
|
+
export _WQA_BY="$QUEUED_BY"
|
|
103
|
+
|
|
104
|
+
BODY=$(jq -n '{
|
|
105
|
+
vaultPath: env._WQA_VAULT,
|
|
106
|
+
queuedBy: env._WQA_BY,
|
|
107
|
+
sourceType: env._WQA_TYPE,
|
|
108
|
+
sourceRef: env._WQA_REF,
|
|
109
|
+
content: env._WQA_CONTENT,
|
|
110
|
+
reason: env._WQA_REASON
|
|
111
|
+
}')
|
|
112
|
+
|
|
113
|
+
unset _WQA_VAULT _WQA_CONTENT _WQA_REASON _WQA_REF _WQA_TYPE _WQA_BY
|
|
114
|
+
|
|
115
|
+
api_call POST "/wiki/queue" "$BODY"
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wiki REST Controller
|
|
3
|
+
*
|
|
4
|
+
* Exposes the LLM-wiki ingest/query operations over HTTP so the bash
|
|
5
|
+
* skills (`wiki-ingest`, `wiki-query`) and in-process subscribers
|
|
6
|
+
* (`WikiChatSubscriberService`) all funnel through the same code path.
|
|
7
|
+
*
|
|
8
|
+
* @module controllers/wiki/wiki.controller
|
|
9
|
+
*/
|
|
10
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
11
|
+
/**
|
|
12
|
+
* POST /api/wiki/ingest
|
|
13
|
+
*
|
|
14
|
+
* Write a single source into a vault's `llm-curated/log.md` (or other
|
|
15
|
+
* non-frozen target). The handler enforces request validation; per-call
|
|
16
|
+
* routing / frozen-path / size limits live in `WikiIngestService`.
|
|
17
|
+
*
|
|
18
|
+
* Request body:
|
|
19
|
+
* {
|
|
20
|
+
* vaultPath: string,
|
|
21
|
+
* sourceType: WikiSourceType,
|
|
22
|
+
* sourceRef: string,
|
|
23
|
+
* sourceBody: string,
|
|
24
|
+
* callerSession?: string,
|
|
25
|
+
* targetRelativePath?: string
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* Response:
|
|
29
|
+
* 200 { success: true, result: WikiIngestOutcome (ok=true variant) }
|
|
30
|
+
* 400 { success: false, error: string, outcome?: WikiIngestOutcome }
|
|
31
|
+
* 422 { success: false, error: 'frozen_path', outcome: WikiIngestOutcome }
|
|
32
|
+
*/
|
|
33
|
+
export declare function ingest(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* POST /api/wiki/query
|
|
36
|
+
*
|
|
37
|
+
* Build the system-context payload for a single-vault read. The skill /
|
|
38
|
+
* caller's runtime concatenates this with its per-LLM task-instruction
|
|
39
|
+
* prompt (`config/skills/<role>/wiki-query/prompts/<runtime>.md`) before
|
|
40
|
+
* the actual LLM call.
|
|
41
|
+
*
|
|
42
|
+
* Request body:
|
|
43
|
+
* {
|
|
44
|
+
* vaultPath: string,
|
|
45
|
+
* query: string,
|
|
46
|
+
* topK?: number,
|
|
47
|
+
* recentLogEntries?: number
|
|
48
|
+
* }
|
|
49
|
+
*
|
|
50
|
+
* Response:
|
|
51
|
+
* 200 { success: true, result: { context: WikiQuerySystemContext } }
|
|
52
|
+
* 400 { success: false, error: string, outcome?: failure }
|
|
53
|
+
* 404 { success: false, error: 'schema_missing', outcome }
|
|
54
|
+
*/
|
|
55
|
+
export declare function queryVault(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* POST /api/wiki/queue
|
|
58
|
+
*
|
|
59
|
+
* Enqueue a candidate item. Agents call this when a turn produces
|
|
60
|
+
* content worth saving to the wiki. The `reason` is REQUIRED — the
|
|
61
|
+
* agent has to justify why this is wiki-worthy (audit trail + helps
|
|
62
|
+
* the processor decide where it goes).
|
|
63
|
+
*/
|
|
64
|
+
export declare function queueAdd(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* GET /api/wiki/queue?vaultPath=…&status=…&queuedBy=…&limit=…
|
|
67
|
+
*/
|
|
68
|
+
export declare function queueList(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* POST /api/wiki/queue/:id/claim
|
|
71
|
+
* body: { claimedBy: string }
|
|
72
|
+
*/
|
|
73
|
+
export declare function queueClaim(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* POST /api/wiki/queue/:id/process
|
|
76
|
+
* body: { ingested: boolean, pagesWritten?: string[], targetPath?: string, summary?: string }
|
|
77
|
+
*/
|
|
78
|
+
export declare function queueProcess(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* POST /api/wiki/queue/:id/skip
|
|
81
|
+
* body: { skipReason: string }
|
|
82
|
+
*/
|
|
83
|
+
export declare function queueSkip(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* POST /api/wiki/queue/claim-next
|
|
86
|
+
* body: { claimedBy: string, vaultPath?: string, offset?: number, topK?: number, recentLogEntries?: number }
|
|
87
|
+
*
|
|
88
|
+
* Claims the next pending item AND returns the vault context the
|
|
89
|
+
* agent's LLM should classify against. The agent then picks a target
|
|
90
|
+
* page, calls /wiki/ingest, and commits via /queue/:id/process.
|
|
91
|
+
*/
|
|
92
|
+
export declare function queueClaimNext(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* POST /api/wiki/bookkeep
|
|
95
|
+
* body: { vaultPath: string, windowDays?: number, threshold?: number }
|
|
96
|
+
*/
|
|
97
|
+
export declare function bookkeep(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* GET /api/wiki/vaults
|
|
100
|
+
*
|
|
101
|
+
* Returns the list of all known vaults (project + team + global) with
|
|
102
|
+
* stats so the UI can render a sidebar. Discovery uses the same logic
|
|
103
|
+
* the bookkeep trigger uses.
|
|
104
|
+
*/
|
|
105
|
+
export declare function listVaults(_req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
106
|
+
/**
|
|
107
|
+
* GET /api/wiki/tree?vaultPath=...
|
|
108
|
+
*
|
|
109
|
+
* Walks the vault directory and returns the file tree. Frozen folders
|
|
110
|
+
* are marked so the UI can render them differently. SCHEMA.md is
|
|
111
|
+
* surfaced as a top-level file.
|
|
112
|
+
*/
|
|
113
|
+
export declare function getVaultTree(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
114
|
+
/**
|
|
115
|
+
* GET /api/wiki/page?vaultPath=...&relativePath=...
|
|
116
|
+
*
|
|
117
|
+
* Returns the raw markdown content of a single page. The relativePath
|
|
118
|
+
* is validated to ensure it doesn't escape the vault directory.
|
|
119
|
+
*/
|
|
120
|
+
export declare function getPage(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
121
|
+
/**
|
|
122
|
+
* POST /api/wiki/bookkeep/trigger-now
|
|
123
|
+
*
|
|
124
|
+
* Force one tick of the bookkeep trigger NOW. Used for manual testing
|
|
125
|
+
* (curl, the chat UI, an admin button) — production cadence is the
|
|
126
|
+
* automatic interval scan, but operators sometimes want to invoke it
|
|
127
|
+
* synchronously to verify wiring or to clear a backlog.
|
|
128
|
+
*/
|
|
129
|
+
export declare function bookkeepTriggerNow(_req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
130
|
+
/**
|
|
131
|
+
* GET /api/wiki/queue/stats?vaultPath=…
|
|
132
|
+
*/
|
|
133
|
+
export declare function queueStats(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
134
|
+
//# sourceMappingURL=wiki.controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wiki.controller.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/wiki/wiki.controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AA+B/D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,MAAM,CAC1B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAmEf;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAgDf;AAgBD;;;;;;;GAOG;AACH,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAwDf;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CA+Bf;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAmCf;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CA+Bf;AAwBD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAmDf;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAqFf;AAQD;;;;;GAKG;AACH,wBAAsB,OAAO,CAC3B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAmDf;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAQf"}
|