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.
Files changed (75) hide show
  1. package/config/roles/_common/wiki-instructions.md +33 -0
  2. package/config/roles/orchestrator/prompt.md +35 -0
  3. package/config/roles/team-leader/prompt.md +38 -0
  4. package/config/skills/agent/core/wiki-query/SKILL.md +66 -0
  5. package/config/skills/agent/core/wiki-query/execute.sh +107 -0
  6. package/config/skills/orchestrator/wiki-bookkeep/SKILL.md +71 -0
  7. package/config/skills/orchestrator/wiki-bookkeep/execute.sh +72 -0
  8. package/config/skills/orchestrator/wiki-ingest/SKILL.md +63 -0
  9. package/config/skills/orchestrator/wiki-ingest/execute.sh +113 -0
  10. package/config/skills/orchestrator/wiki-process-queue/SKILL.md +71 -0
  11. package/config/skills/orchestrator/wiki-process-queue/execute.sh +93 -0
  12. package/config/skills/orchestrator/wiki-queue-add/SKILL.md +89 -0
  13. package/config/skills/orchestrator/wiki-queue-add/execute.sh +115 -0
  14. package/dist/backend/backend/src/controllers/wiki/wiki.controller.d.ts +134 -0
  15. package/dist/backend/backend/src/controllers/wiki/wiki.controller.d.ts.map +1 -0
  16. package/dist/backend/backend/src/controllers/wiki/wiki.controller.js +718 -0
  17. package/dist/backend/backend/src/controllers/wiki/wiki.controller.js.map +1 -0
  18. package/dist/backend/backend/src/controllers/wiki/wiki.routes.d.ts +23 -0
  19. package/dist/backend/backend/src/controllers/wiki/wiki.routes.d.ts.map +1 -0
  20. package/dist/backend/backend/src/controllers/wiki/wiki.routes.js +43 -0
  21. package/dist/backend/backend/src/controllers/wiki/wiki.routes.js.map +1 -0
  22. package/dist/backend/backend/src/index.d.ts.map +1 -1
  23. package/dist/backend/backend/src/index.js +39 -0
  24. package/dist/backend/backend/src/index.js.map +1 -1
  25. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  26. package/dist/backend/backend/src/routes/api.routes.js +4 -0
  27. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  28. package/dist/backend/backend/src/services/session/pty/pty-session.d.ts +28 -0
  29. package/dist/backend/backend/src/services/session/pty/pty-session.d.ts.map +1 -1
  30. package/dist/backend/backend/src/services/session/pty/pty-session.js +162 -4
  31. package/dist/backend/backend/src/services/session/pty/pty-session.js.map +1 -1
  32. package/dist/backend/backend/src/services/wiki/referenced-by.resolver.d.ts +69 -0
  33. package/dist/backend/backend/src/services/wiki/referenced-by.resolver.d.ts.map +1 -0
  34. package/dist/backend/backend/src/services/wiki/referenced-by.resolver.js +174 -0
  35. package/dist/backend/backend/src/services/wiki/referenced-by.resolver.js.map +1 -0
  36. package/dist/backend/backend/src/services/wiki/schema-loader.service.d.ts +57 -0
  37. package/dist/backend/backend/src/services/wiki/schema-loader.service.d.ts.map +1 -0
  38. package/dist/backend/backend/src/services/wiki/schema-loader.service.js +183 -0
  39. package/dist/backend/backend/src/services/wiki/schema-loader.service.js.map +1 -0
  40. package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.d.ts +86 -0
  41. package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.d.ts.map +1 -0
  42. package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.js +187 -0
  43. package/dist/backend/backend/src/services/wiki/wiki-bookkeep-trigger.service.js.map +1 -0
  44. package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.d.ts +116 -0
  45. package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.d.ts.map +1 -0
  46. package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.js +299 -0
  47. package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.js.map +1 -0
  48. package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.d.ts +74 -0
  49. package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.d.ts.map +1 -0
  50. package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.js +154 -0
  51. package/dist/backend/backend/src/services/wiki/wiki-chat-subscriber.service.js.map +1 -0
  52. package/dist/backend/backend/src/services/wiki/wiki-ingest.service.d.ts +100 -0
  53. package/dist/backend/backend/src/services/wiki/wiki-ingest.service.d.ts.map +1 -0
  54. package/dist/backend/backend/src/services/wiki/wiki-ingest.service.js +212 -0
  55. package/dist/backend/backend/src/services/wiki/wiki-ingest.service.js.map +1 -0
  56. package/dist/backend/backend/src/services/wiki/wiki-process.service.d.ts +84 -0
  57. package/dist/backend/backend/src/services/wiki/wiki-process.service.d.ts.map +1 -0
  58. package/dist/backend/backend/src/services/wiki/wiki-process.service.js +138 -0
  59. package/dist/backend/backend/src/services/wiki/wiki-process.service.js.map +1 -0
  60. package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts +115 -0
  61. package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts.map +1 -0
  62. package/dist/backend/backend/src/services/wiki/wiki-query.service.js +291 -0
  63. package/dist/backend/backend/src/services/wiki/wiki-query.service.js.map +1 -0
  64. package/dist/backend/backend/src/services/wiki/wiki-queue.service.d.ts +115 -0
  65. package/dist/backend/backend/src/services/wiki/wiki-queue.service.d.ts.map +1 -0
  66. package/dist/backend/backend/src/services/wiki/wiki-queue.service.js +261 -0
  67. package/dist/backend/backend/src/services/wiki/wiki-queue.service.js.map +1 -0
  68. package/dist/backend/backend/src/services/wiki/wiki.types.d.ts +84 -0
  69. package/dist/backend/backend/src/services/wiki/wiki.types.d.ts.map +1 -0
  70. package/dist/backend/backend/src/services/wiki/wiki.types.js +10 -0
  71. package/dist/backend/backend/src/services/wiki/wiki.types.js.map +1 -0
  72. package/frontend/dist/assets/{index-b279da34.js → index-cc115bb4.js} +246 -246
  73. package/frontend/dist/assets/{index-c07e04c0.css → index-db3f5041.css} +1 -1
  74. package/frontend/dist/index.html +2 -2
  75. 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"}