superclawd 0.1.87 → 0.1.89
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/dist/hook-helper.mjs +25 -25
- package/dist/index.js +94 -88
- package/dist/mcp-server.mjs +17 -17
- package/package.json +2 -2
package/dist/hook-helper.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire as __cr } from 'module'; const require = __cr(import.meta.url);
|
|
2
|
-
import{readFileSync as y,writeFileSync as K,appendFileSync as Ue,existsSync as L,readdirSync as $e,statSync as X,unlinkSync as We}from"node:fs";import{basename as Ye}from"node:path";import{homedir as Je}from"node:os";import{pathToFileURL as je}from"node:url";var Q=["You maintain the durable memory for ONE repository. You review a FINISHED coding session and RECONCILE what it taught against the memories ALREADY SAVED (shown below with ids), keeping the set accurate, current, and non-redundant for the NEXT session. ","SAVE or UPDATE a fact when it would save a newcomer real time or prevent a wrong turn \u2014 for example: the build/test/run command (especially anything non-default, e.g. a subdirectory or required env flags); where key code or config lives when the layout is non-obvious (e.g. the app is in a subdirectory, or content is data-driven from one file); a setup step or arrangement needed to make things work (e.g. ESM-only deps must be mocked for tests to run); a correction to a reasonable wrong assumption (e.g. the repo uses npm despite a pnpm convention); or a non-obvious gotcha and its fix. A fact STILL qualifies even if it 'could be figured out by reading the files'. ","NEVER save: secrets or credentials; code dumps; transient state (a test that merely happened to pass or fail this run); one-off task details; or truly trivial facts (e.g. 'this is a React project', or that a file exists). ","NEVER bake VOLATILE SuperClawd identifiers into a fact: a workflow/skill/command/agent SLUG or id, or a tool-invocation recipe like 'call get_workflow with <slug>'. These break the moment the entity is renamed. Refer to an entity by its human NAME (e.g. the 'Code Review Process' workflow), or omit the identifier entirely. ","CRITICAL \u2014 the ALREADY-SAVED list is the ONLY knowledge future sessions have. If it is NONE, this repo has ZERO saved knowledge: nobody knows the build command, the package manager, or where the app lives \u2014 so the session's basic orientation facts (build/test command, package manager, where the app actually lives, key setup steps) are exactly what the first memories should record. Never call a fact 'already known' or 'standard' \u2014 judge only against the literal list. ","Emit OPERATIONS against the existing set: ",'\u2022 "create" \u2014 a genuinely NEW fact not represented by any existing memory. ','\u2022 "update" \u2014 the session REFINES, SHARPENS, or CORRECTS an existing memory: cite its id and rewrite its COMPLETE body to the now-correct version. Prefer update over create whenever an existing memory is about the same thing (the package manager, the app location, the build command, \u2026), even if the wording differs. A correction (e.g. the app moved from apps/web to apps/app) is an UPDATE to that memory, NOT a new one. When you correct a fact, also UPDATE any OTHER memory that still references the now-stale version. ',"\u2022 Omit any fact already captured accurately (no op). ","A memory tagged [LOCKED] is read-only: never update it; you may only create a complementary fact. ","Keep the set MINIMAL and CURRENT: never leave two memories about the same thing, and never leave an outdated fact beside its correction. ",'CRITICAL \u2014 within THIS single response, every fact must end up in EXACTLY ONE memory: never emit a "create" whose content is already covered by (or overlaps) a memory you keep or "update" in the same response. If the session adds a fact related to an existing memory, FOLD it into that memory with ONE "update" \u2014 do NOT also create a separate memory for the same fact. ',"This is a ONE-SHOT reconciliation of an already-finished session \u2014 do NOT continue the work, ask questions, or take any action. ",`Every op MUST include a "title": a distilled, human one-line SUMMARY of its body (<=120 chars) \u2014 a real summary, NOT the body's first words copied verbatim. `,'Respond with ONLY a strict JSON object {"ops":[ ... ],"reason":"<short overall why>"} and nothing else. Each op is {"op":"create","title":"<=120-char summary","body":"<self-contained 1-4 sentence note with concrete commands/paths + the gotcha & its fix>"} or {"op":"update","id":"<existing id>","title":"<=120-char summary","body":"<rewritten complete note>"}. If the session taught nothing durable, return {"ops":[],"reason":"..."}.'].join(""),ee=["You review a FINISHED coding session and RECONCILE what it taught against the memories ALREADY SAVED (shown below with ids), keeping each memory set accurate, current, and non-redundant for the NEXT session. You maintain TWO memory sets and route every op to the correct one: ",'\u2022 "repo" \u2014 durable knowledge about THIS repository, SHARED with the whole team: the build/test/run command (especially non-default ones, e.g. a subdirectory or required env flags); where key code/config lives when non-obvious; a required setup step (e.g. an ESM-only dep must be mocked for tests); a correction to a wrong assumption; or a non-obvious gotcha and its fix. A rule about the codebase, the product, or how the TEAM works is "repo" EVEN IF the user phrases it as "I want\u2026", "always\u2026", or "going forward\u2026". A fact STILL qualifies even if it could be figured out by reading the files. ',`\u2022 "private" \u2014 a preference PRIVATE to THIS individual user about how THEY themselves want to work or be treated: tone/verbosity, what to call them, their experience level, editor/workflow habits, how the assistant should behave toward them specifically. NEVER shared with the team. ONLY for preferences about the person themselves \u2014 never about the code or the team's process. `,'Route each fact by what it is ABOUT \u2014 the WORK/team (repo) or the PERSON (private). Do NOT require the user to label something "private"; infer it. When genuinely unsure whether a stated preference is a team convention or a private one, treat it as "repo" (shared): never leak a team rule into a private memory, and never put a genuinely private preference into the shared repo set. ',"NEVER save (either set): secrets or credentials; code dumps; transient state (a test that merely passed/failed this run); one-off task details; trivia. ","NEVER bake VOLATILE SuperClawd identifiers into a fact: a workflow/skill/command/agent SLUG or id, or a tool-invocation recipe like 'call get_workflow with <slug>'. These break the moment the entity is renamed. Refer to an entity by its human NAME, or omit the identifier entirely. ","CRITICAL \u2014 the ALREADY-SAVED lists are the ONLY knowledge future sessions have. If a set is NONE it has ZERO saved knowledge (nobody knows the build command, package manager, or where the app lives), so the session's basic orientation facts are exactly what its first memories should record. Judge 'already known' only against the literal lists, never against what is 'standard'. ","Emit OPERATIONS, each tagged with its scope: ",'\u2022 {"op":"create","scope":"repo"|"private","body":"<self-contained note>"} \u2014 a genuinely NEW fact/preference not represented by any existing memory in that set. ','\u2022 {"op":"update","scope":"repo","id":"<existing repo id>","body":"<rewritten COMPLETE body>"} \u2014 the session REFINES, SHARPENS, or CORRECTS an existing REPO memory: prefer update over create whenever an existing repo memory is about the same thing (the package manager, the app location, \u2026); a correction (e.g. the app moved from apps/web to apps/app) is an UPDATE, not a new memory; also update any other repo memory that still references a now-stale fact. UPDATE applies to the repo set ONLY. ','\u2022 For the PRIVATE set, emit ONLY "create" for a genuinely new preference \u2014 never update or restate one already saved (the user curates their private memories themselves); omit (no op) any private preference already captured. ',"\u2022 Omit any fact already captured accurately (no op). ","A memory tagged [LOCKED] is read-only: never update it; you may only create a complementary fact. ","Keep each set MINIMAL and CURRENT: never leave two memories about the same thing, and never leave an outdated fact beside its correction. ",'CRITICAL \u2014 within THIS single response, every fact must end up in EXACTLY ONE memory of its set: never emit a "create" whose content is already covered by (or overlaps) a memory you keep or "update" in the same response. If the session adds a fact related to an existing memory, FOLD it into that memory with ONE "update" \u2014 do NOT also create a separate memory for the same fact. ',"This is a ONE-SHOT reconciliation of an already-finished session \u2014 do NOT continue the work, ask questions, or take any action. ",`Every op MUST include a "title": a distilled, human one-line SUMMARY of its body (<=120 chars) \u2014 a real summary, NOT the body's first words copied verbatim. `,'Respond with ONLY a strict JSON object {"ops":[ ... ],"reason":"<short overall why>"} and nothing else. Each op is {"op":"create","scope":"repo"|"private","title":"<=120-char summary","body":"..."} or {"op":"update","scope":"repo","id":"<existing id>","title":"<=120-char summary","body":"..."}. If the session taught nothing durable, return {"ops":[],"reason":"..."}.'].join(""),te=["You maintain the durable lessons for a single reusable AGENT (a specialist invoked to do a job). You review a FINISHED run and RECONCILE what it learned about HOW TO PERFORM ITS ROLE against the lessons ALREADY SAVED (shown below with ids), keeping the set accurate, current, and non-redundant for the agent's NEXT invocation (in ANY repository). ","SAVE or UPDATE a lesson when it would make this agent do its job better next time: a standing preference or convention the user/team established for its work, a correction to how it should operate, or a recurring gotcha in its domain and how to handle it. Lessons are about the ROLE, not a codebase \u2014 they qualify regardless of which repo this run happened in. ","NEVER save: secrets or credentials; code dumps; one-off task details specific only to THIS single run; transient state; or truly trivial facts. ","NEVER record a lesson about TOOL AVAILABILITY \u2014 e.g. that a tool 'does not exist', 'is unavailable', 'is not in the toolset', or that a call failed because the tool wasn't callable. Which tools a run can call is an environment/config detail set per-invocation (this agent runs with a RESTRICTED toolset that omits tools the main session has), NOT a durable fact about the role: the tool may well exist and be available in another context, so such a lesson is misleading and goes stale. Treat a 'no such tool' / 'tool not found' error as a transient environment artifact, never a lesson. ","The ALREADY-SAVED list is the ONLY knowledge the agent carries between runs \u2014 treat anything NOT listed as new; never claim a lesson is 'already known' unless it literally appears. ","IMPORTANT \u2014 the agent runs under workspace SKILLS, instructions, and guardrails that you CANNOT see in this transcript. So: do NOT treat an asserted convention, rule, or guideline as fabricated or 'hallucinated' merely because the transcript shows no basis for it \u2014 it may come from the agent's hidden instructions. NEVER record a lesson that tells the agent to stop asserting conventions, to second-guess its guidance, or that is based on YOUR OWN judgment that the agent made a mistake this run. Capture a lesson ONLY when the run itself shows the USER establishing or correcting a standing preference, or a concrete reproducible domain gotcha the agent itself confirmed. ","Emit OPERATIONS against the existing set: ",'\u2022 "create" \u2014 a genuinely NEW lesson not represented by any existing one. ','\u2022 "update" \u2014 the run REFINES or CORRECTS an existing lesson: cite its id and rewrite its COMPLETE body. Prefer update over create whenever an existing lesson is about the same thing, even if the wording differs. ',"\u2022 Omit any lesson already captured accurately (no op). ","A lesson tagged [LOCKED] is read-only: never update it; you may only create a complementary lesson. ","Keep the set MINIMAL and CURRENT: never leave two lessons about the same thing, and never leave an outdated lesson beside its correction. ",'CRITICAL \u2014 within THIS single response, every lesson must end up exactly ONCE: never emit a "create" whose content is already covered by (or overlaps) a lesson you keep or "update" in the same response. If the run adds something related to an existing lesson, FOLD it in with ONE "update" \u2014 do NOT also create a separate lesson for the same thing. ',"This is a ONE-SHOT reconciliation of an already-finished run \u2014 do NOT continue the work, ask questions, or take any action. ",`Every op MUST include a "title": a distilled, human one-line SUMMARY of its lesson (<=120 chars) \u2014 a real summary, NOT the lesson's first words copied verbatim. `,'Respond with ONLY a strict JSON object {"ops":[ ... ],"reason":"<short overall why>"} and nothing else. Each op is {"op":"create","title":"<=120-char summary","body":"<self-contained instruction the agent can apply next time>"} or {"op":"update","id":"<existing id>","title":"<=120-char summary","body":"<rewritten complete lesson>"}. If the run taught nothing durable, return {"ops":[],"reason":"..."}.'].join("");var ne=["You decide whether a code change makes a remembered lesson STALE (no longer true).",'Respond ONLY strict JSON {"verdict":"stale"|"valid","reason":"<one line>","confidence":<0..1>}.'].join(" ");import{randomUUID as ge}from"node:crypto";import{spawn as x,execSync as D}from"node:child_process";var Re=`SUPERCLAWD \u2014 operating manual (always in effect):
|
|
2
|
+
import{readFileSync as h,writeFileSync as G,appendFileSync as We,existsSync as I,readdirSync as Ye,statSync as q,unlinkSync as Fe}from"node:fs";import{basename as Je}from"node:path";import{homedir as je}from"node:os";import{pathToFileURL as Ge}from"node:url";var Z=["You maintain the durable memory for ONE repository. You review a FINISHED coding session and RECONCILE what it taught against the memories ALREADY SAVED (shown below with ids), keeping the set accurate, current, and non-redundant for the NEXT session. ","SAVE or UPDATE a fact when it would save a newcomer real time or prevent a wrong turn \u2014 for example: the build/test/run command (especially anything non-default, e.g. a subdirectory or required env flags); where key code or config lives when the layout is non-obvious (e.g. the app is in a subdirectory, or content is data-driven from one file); a setup step or arrangement needed to make things work (e.g. ESM-only deps must be mocked for tests to run); a correction to a reasonable wrong assumption (e.g. the repo uses npm despite a pnpm convention); or a non-obvious gotcha and its fix. A fact STILL qualifies even if it 'could be figured out by reading the files'. ","NEVER save: secrets or credentials; code dumps; transient state (a test that merely happened to pass or fail this run); one-off task details; or truly trivial facts (e.g. 'this is a React project', or that a file exists). ","NEVER bake VOLATILE SuperClawd identifiers into a fact: a workflow/skill/command/agent SLUG or id, or a tool-invocation recipe like 'call get_workflow with <slug>'. These break the moment the entity is renamed. Refer to an entity by its human NAME (e.g. the 'Code Review Process' workflow), or omit the identifier entirely. ","CRITICAL \u2014 the ALREADY-SAVED list is the ONLY knowledge future sessions have. If it is NONE, this repo has ZERO saved knowledge: nobody knows the build command, the package manager, or where the app lives \u2014 so the session's basic orientation facts (build/test command, package manager, where the app actually lives, key setup steps) are exactly what the first memories should record. Never call a fact 'already known' or 'standard' \u2014 judge only against the literal list. ","Emit OPERATIONS against the existing set: ",'\u2022 "create" \u2014 a genuinely NEW fact not represented by any existing memory. ','\u2022 "update" \u2014 the session REFINES, SHARPENS, or CORRECTS an existing memory: cite its id and rewrite its COMPLETE body to the now-correct version. Prefer update over create whenever an existing memory is about the same thing (the package manager, the app location, the build command, \u2026), even if the wording differs. A correction (e.g. the app moved from apps/web to apps/app) is an UPDATE to that memory, NOT a new one. When you correct a fact, also UPDATE any OTHER memory that still references the now-stale version. ',"\u2022 Omit any fact already captured accurately (no op). ","A memory tagged [LOCKED] is read-only: never update it; you may only create a complementary fact. ","Keep the set MINIMAL and CURRENT: never leave two memories about the same thing, and never leave an outdated fact beside its correction. ",'CRITICAL \u2014 within THIS single response, every fact must end up in EXACTLY ONE memory: never emit a "create" whose content is already covered by (or overlaps) a memory you keep or "update" in the same response. If the session adds a fact related to an existing memory, FOLD it into that memory with ONE "update" \u2014 do NOT also create a separate memory for the same fact. ',"This is a ONE-SHOT reconciliation of an already-finished session \u2014 do NOT continue the work, ask questions, or take any action. ",`Every op MUST include a "title": a distilled, human one-line SUMMARY of its body (<=120 chars) \u2014 a real summary, NOT the body's first words copied verbatim. `,'Respond with ONLY a strict JSON object {"ops":[ ... ],"reason":"<short overall why>"} and nothing else. Each op is {"op":"create","title":"<=120-char summary","body":"<self-contained 1-4 sentence note with concrete commands/paths + the gotcha & its fix>"} or {"op":"update","id":"<existing id>","title":"<=120-char summary","body":"<rewritten complete note>"}. If the session taught nothing durable, return {"ops":[],"reason":"..."}.'].join(""),Q=["You review a FINISHED coding session and RECONCILE what it taught against the memories ALREADY SAVED (shown below with ids), keeping each memory set accurate, current, and non-redundant for the NEXT session. You maintain TWO memory sets and route every op to the correct one: ",'\u2022 "repo" \u2014 durable knowledge about THIS repository, SHARED with the whole team: the build/test/run command (especially non-default ones, e.g. a subdirectory or required env flags); where key code/config lives when non-obvious; a required setup step (e.g. an ESM-only dep must be mocked for tests); a correction to a wrong assumption; or a non-obvious gotcha and its fix. A rule about the codebase, the product, or how the TEAM works is "repo" EVEN IF the user phrases it as "I want\u2026", "always\u2026", or "going forward\u2026". A fact STILL qualifies even if it could be figured out by reading the files. ',`\u2022 "private" \u2014 a preference PRIVATE to THIS individual user about how THEY themselves want to work or be treated: tone/verbosity, what to call them, their experience level, editor/workflow habits, how the assistant should behave toward them specifically. NEVER shared with the team. ONLY for preferences about the person themselves \u2014 never about the code or the team's process. `,'Route each fact by what it is ABOUT \u2014 the WORK/team (repo) or the PERSON (private). Do NOT require the user to label something "private"; infer it. When genuinely unsure whether a stated preference is a team convention or a private one, treat it as "repo" (shared): never leak a team rule into a private memory, and never put a genuinely private preference into the shared repo set. ',"NEVER save (either set): secrets or credentials; code dumps; transient state (a test that merely passed/failed this run); one-off task details; trivia. ","NEVER bake VOLATILE SuperClawd identifiers into a fact: a workflow/skill/command/agent SLUG or id, or a tool-invocation recipe like 'call get_workflow with <slug>'. These break the moment the entity is renamed. Refer to an entity by its human NAME, or omit the identifier entirely. ","CRITICAL \u2014 the ALREADY-SAVED lists are the ONLY knowledge future sessions have. If a set is NONE it has ZERO saved knowledge (nobody knows the build command, package manager, or where the app lives), so the session's basic orientation facts are exactly what its first memories should record. Judge 'already known' only against the literal lists, never against what is 'standard'. ","Emit OPERATIONS, each tagged with its scope: ",'\u2022 {"op":"create","scope":"repo"|"private","body":"<self-contained note>"} \u2014 a genuinely NEW fact/preference not represented by any existing memory in that set. ','\u2022 {"op":"update","scope":"repo","id":"<existing repo id>","body":"<rewritten COMPLETE body>"} \u2014 the session REFINES, SHARPENS, or CORRECTS an existing REPO memory: prefer update over create whenever an existing repo memory is about the same thing (the package manager, the app location, \u2026); a correction (e.g. the app moved from apps/web to apps/app) is an UPDATE, not a new memory; also update any other repo memory that still references a now-stale fact. UPDATE applies to the repo set ONLY. ','\u2022 For the PRIVATE set, emit ONLY "create" for a genuinely new preference \u2014 never update or restate one already saved (the user curates their private memories themselves); omit (no op) any private preference already captured. ',"\u2022 Omit any fact already captured accurately (no op). ","A memory tagged [LOCKED] is read-only: never update it; you may only create a complementary fact. ","Keep each set MINIMAL and CURRENT: never leave two memories about the same thing, and never leave an outdated fact beside its correction. ",'CRITICAL \u2014 within THIS single response, every fact must end up in EXACTLY ONE memory of its set: never emit a "create" whose content is already covered by (or overlaps) a memory you keep or "update" in the same response. If the session adds a fact related to an existing memory, FOLD it into that memory with ONE "update" \u2014 do NOT also create a separate memory for the same fact. ',"This is a ONE-SHOT reconciliation of an already-finished session \u2014 do NOT continue the work, ask questions, or take any action. ",`Every op MUST include a "title": a distilled, human one-line SUMMARY of its body (<=120 chars) \u2014 a real summary, NOT the body's first words copied verbatim. `,'Respond with ONLY a strict JSON object {"ops":[ ... ],"reason":"<short overall why>"} and nothing else. Each op is {"op":"create","scope":"repo"|"private","title":"<=120-char summary","body":"..."} or {"op":"update","scope":"repo","id":"<existing id>","title":"<=120-char summary","body":"..."}. If the session taught nothing durable, return {"ops":[],"reason":"..."}.'].join(""),ee=["You maintain the durable lessons for a single reusable AGENT (a specialist invoked to do a job). You review a FINISHED run and RECONCILE what it learned about HOW TO PERFORM ITS ROLE against the lessons ALREADY SAVED (shown below with ids), keeping the set accurate, current, and non-redundant for the agent's NEXT invocation (in ANY repository). ","SAVE or UPDATE a lesson when it would make this agent do its job better next time: a standing preference or convention the user/team established for its work, a correction to how it should operate, or a recurring gotcha in its domain and how to handle it. Lessons are about the ROLE, not a codebase \u2014 they qualify regardless of which repo this run happened in. ","NEVER save: secrets or credentials; code dumps; one-off task details specific only to THIS single run; transient state; or truly trivial facts. ","NEVER record a lesson about TOOL AVAILABILITY \u2014 e.g. that a tool 'does not exist', 'is unavailable', 'is not in the toolset', or that a call failed because the tool wasn't callable. Which tools a run can call is an environment/config detail set per-invocation (this agent runs with a RESTRICTED toolset that omits tools the main session has), NOT a durable fact about the role: the tool may well exist and be available in another context, so such a lesson is misleading and goes stale. Treat a 'no such tool' / 'tool not found' error as a transient environment artifact, never a lesson. ","The ALREADY-SAVED list is the ONLY knowledge the agent carries between runs \u2014 treat anything NOT listed as new; never claim a lesson is 'already known' unless it literally appears. ","IMPORTANT \u2014 the agent runs under workspace SKILLS, instructions, and guardrails that you CANNOT see in this transcript. So: do NOT treat an asserted convention, rule, or guideline as fabricated or 'hallucinated' merely because the transcript shows no basis for it \u2014 it may come from the agent's hidden instructions. NEVER record a lesson that tells the agent to stop asserting conventions, to second-guess its guidance, or that is based on YOUR OWN judgment that the agent made a mistake this run. Capture a lesson ONLY when the run itself shows the USER establishing or correcting a standing preference, or a concrete reproducible domain gotcha the agent itself confirmed. ","Emit OPERATIONS against the existing set: ",'\u2022 "create" \u2014 a genuinely NEW lesson not represented by any existing one. ','\u2022 "update" \u2014 the run REFINES or CORRECTS an existing lesson: cite its id and rewrite its COMPLETE body. Prefer update over create whenever an existing lesson is about the same thing, even if the wording differs. ',"\u2022 Omit any lesson already captured accurately (no op). ","A lesson tagged [LOCKED] is read-only: never update it; you may only create a complementary lesson. ","Keep the set MINIMAL and CURRENT: never leave two lessons about the same thing, and never leave an outdated lesson beside its correction. ",'CRITICAL \u2014 within THIS single response, every lesson must end up exactly ONCE: never emit a "create" whose content is already covered by (or overlaps) a lesson you keep or "update" in the same response. If the run adds something related to an existing lesson, FOLD it in with ONE "update" \u2014 do NOT also create a separate lesson for the same thing. ',"This is a ONE-SHOT reconciliation of an already-finished run \u2014 do NOT continue the work, ask questions, or take any action. ",`Every op MUST include a "title": a distilled, human one-line SUMMARY of its lesson (<=120 chars) \u2014 a real summary, NOT the lesson's first words copied verbatim. `,'Respond with ONLY a strict JSON object {"ops":[ ... ],"reason":"<short overall why>"} and nothing else. Each op is {"op":"create","title":"<=120-char summary","body":"<self-contained instruction the agent can apply next time>"} or {"op":"update","id":"<existing id>","title":"<=120-char summary","body":"<rewritten complete lesson>"}. If the run taught nothing durable, return {"ops":[],"reason":"..."}.'].join("");var te=["You decide whether a code change makes a remembered lesson STALE (no longer true).",'Respond ONLY strict JSON {"verdict":"stale"|"valid","reason":"<one line>","confidence":<0..1>}.'].join(" ");import{randomUUID as ge}from"node:crypto";import{spawn as L,execSync as x}from"node:child_process";var ne=`SUPERCLAWD \u2014 operating manual (always in effect):
|
|
3
3
|
- The ALWAYS rules below are ALREADY LOADED and active for this entire session.
|
|
4
4
|
Apply them directly to all work. Do NOT call any tool to fetch them \u2014 you
|
|
5
5
|
already have them in full.
|
|
@@ -8,8 +8,7 @@ import{readFileSync as y,writeFileSync as K,appendFileSync as Ue,existsSync as L
|
|
|
8
8
|
the \`get_directives\` tool with that file's skillId (a UUID) BEFORE acting,
|
|
9
9
|
and apply what it returns. Those skill files are pointers, not the rules.
|
|
10
10
|
- Only call \`get_directives\` with a UUID skillId taken from an activated skill
|
|
11
|
-
file. Never call it for the ALWAYS rules, and never pass a skill name
|
|
12
|
-
- MEMORY: when the user states something durable \u2014 a fact, preference, or standing
|
|
11
|
+
file. Never call it for the ALWAYS rules, and never pass a skill name.`,be=`- MEMORY: when the user states something durable \u2014 a fact, preference, or standing
|
|
13
12
|
rule, ESPECIALLY phrased as "remember\u2026", "from now on", "always", or "going
|
|
14
13
|
forward" \u2014 call \`record_memory\` RIGHT AWAY to persist it (silently; it picks the
|
|
15
14
|
scope on its own: the user's PRIVATE memory, the TEAM's, or the REPO's). Acknowledging
|
|
@@ -22,51 +21,52 @@ import{readFileSync as y,writeFileSync as K,appendFileSync as Ue,existsSync as L
|
|
|
22
21
|
\`record_memory\` for it; never claim a preference is "already" a saved convention, or
|
|
23
22
|
that it "will persist", unless you just recorded it (or confirmed it via
|
|
24
23
|
\`list_memories\`). A background pass also captures durable facts at session end as a
|
|
25
|
-
backstop \u2014 but never rely on it for an explicit request; record that now.`;function
|
|
24
|
+
backstop \u2014 but never rely on it for an explicit request; record that now.`;function Oe(n){let e=process.env.SUPERCLAWD_MEMORY_OFF==="1"?ne:`${ne}
|
|
25
|
+
${be}`,t=(n||"").trim();return t&&(e+=`
|
|
26
26
|
|
|
27
27
|
ALWAYS \u2014 foundational rules (already loaded & active for this whole session; apply directly, never fetch):
|
|
28
|
-
${t}`),e}function
|
|
29
|
-
`)[0];if(r&&
|
|
28
|
+
${t}`),e}function M(n,e){return JSON.stringify({hookSpecificOutput:{hookEventName:n,additionalContext:Oe(e)}})}var re="superclawd",ke="core",Ce=`mcp__plugin_${re}_${ke}__`;var Lt=`${Ce}*`,oe=`${re}:`;import{homedir as Pe}from"node:os";import{join as b}from"node:path";import{readFileSync as se,writeFileSync as $t,mkdirSync as Wt,chmodSync as Yt,existsSync as Ft}from"node:fs";var Jt=(process.env.SUPERCLAWD_BACKEND||"real").toLowerCase();var jt=process.env.SUPERCLAWD_MCP_API_URL||"https://mcp-api.superclawd.com",Gt=process.env.SUPERCLAWD_API_URL||"https://api.superclawd.com",ie=process.env.SUPERCLAWD_HOME||b(Pe(),".superclawd"),Ne=b(ie,"sessions"),_e=b(ie,"config.json");function Te(n){if(!n||typeof n!="object")return{};let e=n,t=e.credentials??{...typeof e.keyId=="string"?{keyId:e.keyId}:{},...typeof e.secret=="string"?{secret:e.secret}:{},...typeof e.workspace=="string"?{workspace:e.workspace}:{}},r=e.preferences??{...typeof e.skipPermissions=="boolean"?{skipPermissions:e.skipPermissions}:{},...typeof e.notifications=="boolean"?{notifications:e.notifications}:{},...typeof e.chooseWorkspaceAtStartup=="boolean"?{chooseWorkspaceAtStartup:e.chooseWorkspaceAtStartup}:{},...typeof e.experimental=="boolean"?{experimental:e.experimental}:{}},o={};return Object.keys(t).length&&(o.credentials=t),Object.keys(r).length&&(o.preferences=r),typeof e.machineId=="string"&&(o.machineId=e.machineId),o}function U(){try{return Te(JSON.parse(se(_e,"utf8")))}catch{return null}}function Ie(){return U()?.preferences?.notifications===!0}function k(n){return b(Ne,n)}function Le(n){return b(n,"config.json")}function $(n){try{return JSON.parse(se(Le(n),"utf8"))}catch{return null}}function C(n){let e=n?$(k(n)):null;return e&&typeof e.notifications=="boolean"?e.notifications:Ie()}var Kt=1e3*60*60*24*3;import{existsSync as W}from"node:fs";import{homedir as xe}from"node:os";import{spawn as De,execSync as Me}from"node:child_process";var P="sonnet",Ue=2e4;function O(){let n=process.env.SUPERCLAWD_CLAUDE_BIN;if(n&&W(n))return n;try{let t=process.platform==="win32"?"where claude":"command -v claude",r=Me(t,{encoding:"utf8"}).trim().split(`
|
|
29
|
+
`)[0];if(r&&W(r))return r}catch{}let e=[`${xe()}/.local/bin/claude`,"/opt/homebrew/bin/claude","/usr/local/bin/claude","/usr/bin/claude"];for(let t of e)if(W(t))return t;return null}function ae(n){let e=n.indexOf("{"),t=n.lastIndexOf("}");return e>=0&&t>e?n.slice(e,t+1):n}function $e(n){try{let e=n;try{let r=JSON.parse(n);typeof r.result=="string"&&(e=r.result)}catch{}let t=JSON.parse(ae(e));return typeof t.verdict!="string"||!t.verdict?null:{verdict:t.verdict,reason:typeof t.reason=="string"?t.reason:"",confidence:typeof t.confidence=="number"?t.confidence:1}}catch{return null}}function ce(n){let{system:e,user:t}=n,r=n.model||P,o=n.timeoutMs??Ue,i=O();return i?new Promise(s=>{let a="",c=!1,u=f=>{c||(c=!0,s(f))},l;try{l=De(i,["-p","--model",r,"--output-format","json","--strict-mcp-config","--setting-sources","user","--tools","","--append-system-prompt",e],{stdio:["pipe","pipe","ignore"],env:{...process.env,SUPERCLAWD_POLICY_JUDGE:"1"}})}catch{return u(null)}let d=setTimeout(()=>{try{l.kill("SIGKILL")}catch{}u(null)},o);l.stdout?.on("data",f=>a+=f),l.on("error",()=>{clearTimeout(d),u(null)}),l.on("close",()=>{if(clearTimeout(d),n.onRaw)try{n.onRaw(a)}catch{}u(a)});try{l.stdin?.write(t),l.stdin?.end()}catch{}}):Promise.resolve(null)}function Y(n){return ce(n).then(e=>e?$e(e):null)}function F(n){return ce(n).then(e=>{if(!e)return null;try{let t=e;try{let r=JSON.parse(e);typeof r.result=="string"&&(t=r.result)}catch{}return JSON.parse(ae(t))}catch{return null}})}var g=process.env.SUPERCLAWD_MCP_API_URL||"https://mcp-api.superclawd.com",m=(process.env.SUPERCLAWD_BACKEND||"real").toLowerCase(),S=process.env.SUPERCLAWD_MCP_KEY||"",w=process.env.SUPERCLAWD_MCP_SECRET||"",R=process.env.SUPERCLAWD_MCP_WORKSPACE||"";function _(){let n={"content-type":"application/json","x-mcp-key-id":S,"x-mcp-secret":w,"x-workspace-slug":R,"x-request-id":ge()};return process.env.SUPERCLAWD_EXPERIMENTAL==="true"&&(n["x-experimental"]="true"),process.env.SUPERCLAWD_PRIVATE_MEMORY==="0"&&(n["x-private-memory"]="false"),process.env.SUPERCLAWD_MEMORY_OFF==="1"&&(n["x-superclawd-memory"]="off"),n}async function D(n,e){let t=new AbortController,r=setTimeout(()=>t.abort(),e);try{return await fetch(n,{headers:_(),signal:t.signal})}finally{clearTimeout(r)}}async function Ke(n,e="SessionStart"){let t="";if(n)try{t=h(n,"utf8")}catch{}if(m!=="mock"&&S&&w&&R&&process.env.SUPERCLAWD_FOUNDATIONAL_FROM_LAUNCH!=="1")try{let r=process.env.SUPERCLAWD_REPO_FINGERPRINT,o=`${g}/api/prompt/foundational`+(r?`?repoFingerprint=${encodeURIComponent(r)}`:""),i=await D(o,3e3);if(i.ok){let s=await i.json();typeof s.text=="string"&&(t=s.text)}}catch{}process.stdout.write(M(e,t))}async function Ve(){let n=()=>process.stdout.write(ye),e=()=>process.stdout.write(JSON.stringify({hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:"SuperClawd: out of credits. Top up at app.superclawd.com to load directives."}}));if(m==="mock"||!S||!w||!R)return void n();try{let t=await D(`${g}/api/prompt/balance`,2e3);if(!t.ok)return void n();let o=(await t.json()).content,s=(Array.isArray(o)?o.map(a=>a.text??"").join(""):"").match(/<current_balance>([\d.]+)<\/current_balance>/);return s&&Number(s[1])<=0?void e():void n()}catch{return void n()}}var He=process.env.SUPERCLAWD_POLICY_MODEL||P,Be=Number(process.env.SUPERCLAWD_POLICY_TIMEOUT_MS||6e4),le=6e4,qe=4,Xe=["You are a code-policy judge. Decide whether a staged git diff VIOLATES a single team rule.","Reason briefly about control flow, indirection, and scope \u2014 judge whether the rule is actually","broken, not whether the diff merely touches a related area. If the rule does not apply to this",'diff, the verdict is "ok".','Respond with ONLY strict JSON: {"verdict":"violation"|"ok","reason":"<one line>","confidence":<0..1>}.',"Output nothing else."].join(" ");function ze(n,e){let t=(e.evaluation.examples??[]).map((r,o)=>`Example ${o+1} (verdict: ${r.verdict}):
|
|
30
30
|
${r.diff}`).join(`
|
|
31
31
|
|
|
32
32
|
`);return[`RULE: ${e.rule}`,`CRITERIA: ${e.evaluation.criteria}`,t?`
|
|
33
33
|
LABELED EXAMPLES:
|
|
34
34
|
${t}
|
|
35
35
|
`:"","STAGED DIFF:",n].join(`
|
|
36
|
-
`)}async function
|
|
36
|
+
`)}async function Ze(n,e){let t=await Y({system:Xe,user:ze(n,e),model:He,timeoutMs:Be});return!t||t.verdict!=="violation"&&t.verdict!=="ok"?null:{verdict:t.verdict,reason:t.reason,confidence:t.confidence}}async function Qe(n,e){let t=Math.max(1,Math.min(5,e.evaluation.voteN??1)),r=(await Promise.all(Array.from({length:t},()=>Ze(n,e)))).filter(a=>a!==null);if(r.length===0)return null;let o=r.filter(a=>a.verdict==="violation");if(o.length<=r.length/2)return null;let i=o.reduce((a,c)=>a+c.confidence,0)/o.length,s=e.action;return s==="deny"&&i<.66&&(s="ask"),{name:e.name,action:s,reason:o[0].reason}}var T=60,et=new Set([".git","node_modules","dist","build",".next","coverage",".turbo","vendor"]);function me(n,e){if(e.includes("\0"))return"";let t=e.split(`
|
|
37
37
|
`).map(r=>`+${r}`).join(`
|
|
38
38
|
`);return`diff --git a/${n} b/${n}
|
|
39
39
|
new file
|
|
40
40
|
--- /dev/null
|
|
41
41
|
+++ b/${n}
|
|
42
|
-
${t}`}function
|
|
43
|
-
`)}function
|
|
44
|
-
`).map(c=>c.trim()).filter(Boolean).slice(0,
|
|
45
|
-
`):""}return
|
|
42
|
+
${t}`}function tt(n){let e=n.match(/(?:^|&&|;)\s*cd\s+(?:"([^"]+)"|'([^']+)'|(\S+))/),t=e?e[1]||e[2]||e[3]:"";if(!t)return process.cwd();let r=t.startsWith("/")?t:`${process.cwd()}/${t}`;try{return I(r)?r:process.cwd()}catch{return process.cwd()}}function nt(n){let e=[],t=(r,o)=>{if(e.length>=T)return;let i;try{i=Ye(r)}catch{return}for(let s of i){if(e.length>=T)return;if(s.startsWith("."))continue;let a=`${r}/${s}`,c=o?`${o}/${s}`:s,u=!1;try{u=q(a).isDirectory()}catch{continue}u?et.has(s)||t(a,c):e.push(c)}};return t(n,""),e}function rt(n,e){let t=n.match(/git\s+add\s+([^&;|]+)/),r=[],o=!1;if(t)for(let a of t[1].trim().split(/\s+/))a==="-A"||a==="."||a==="--all"||a==="-a"?o=!0:a.startsWith("-")||r.push(a.replace(/^["']|["']$/g,""));else o=!0;let i=o||r.length===0?nt(e):r,s=[];for(let a of i.slice(0,T))try{let c=me(a,h(`${e}/${a}`,"utf8"));c&&s.push(c)}catch{}return s.join(`
|
|
43
|
+
`)}function ot(n){let e=tt(n),t=o=>{try{return x(o,{cwd:e,encoding:"utf8",maxBuffer:10*1024*1024})}catch{return""}};if(t("git rev-parse --is-inside-work-tree").trim()==="true"){let o=t("git diff --cached");if(o.trim())return o;let i=[],s=t("git diff");s.trim()&&i.push(s);let a=t("git ls-files --others --exclude-standard").split(`
|
|
44
|
+
`).map(c=>c.trim()).filter(Boolean).slice(0,T);for(let c of a)try{let u=me(c,h(`${e}/${c}`,"utf8"));u&&i.push(u)}catch{}return i.join("").trim()?i.join(`
|
|
45
|
+
`):""}return rt(n,e)}async function st(n,e){let t=()=>process.stdout.write(ye);if(process.env.SUPERCLAWD_POLICY_JUDGE==="1")return void t();let r="",o="";try{let c=JSON.parse(e);o=c.tool_name??"",r=c.tool_input?.command??""}catch{return void t()}if(!(o==="Bash"&&/\bgit\s+commit\b/.test(r)))return void t();let s=[];try{if(n){let c=JSON.parse(h(n,"utf8"));Array.isArray(c)&&(s=c)}}catch{return void t()}if(s.length===0||!O())return void t();let a=ot(r);if(!a.trim())return void t();a.length>le&&(a=a.slice(0,le));try{let c=(await he(s,qe,f=>Qe(a,f))).filter(f=>f!==null);if(c.length===0)return void t();let u={deny:3,ask:2,warn:1},l=c.reduce((f,v)=>u[v.action]>u[f.action]?v:f),d=`SuperClawd policy "${l.name}": ${l.reason||l.action}`;process.stdout.write(JSON.stringify(l.action==="warn"?{hookSpecificOutput:{hookEventName:"PreToolUse",additionalContext:d}}:{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:l.action,permissionDecisionReason:d}}))}catch{return void t()}}var ue=6e4,it=4;async function he(n,e,t){let r=new Array(n.length).fill(null),o=0,i=Array.from({length:Math.max(1,Math.min(e,n.length))},async()=>{for(;;){let s=o++;if(s>=n.length)return;try{r[s]=await t(n[s],s)}catch{r[s]=null}}});return await Promise.all(i),r}async function at(){let n=process.env.SUPERCLAWD_REPO_FINGERPRINT||"";if(m==="mock"||!S||!w||!R||!n)return;let e=c=>{try{return x(c,{cwd:process.cwd(),encoding:"utf8",maxBuffer:10*1024*1024,stdio:["ignore","pipe","ignore"]})}catch{return""}},t=e("git rev-parse HEAD").trim();if(!t)return;let r=e("git show --format= -p HEAD");if(!r.trim())return;r.length>ue&&(r=r.slice(0,ue));let o=[];try{let c=`${g}/api/prompt/memories?scope=repo&scopeKey=${encodeURIComponent(n)}`,u=await D(c,4e3);if(!u.ok)return;o=(await u.json().catch(()=>({}))).memories??[]}catch{return}if(o.length===0)return;let i=await he(o,it,async c=>{let u=c.body??c.title??"";if(!u.trim())return null;let l=await Y({system:te,user:`LESSON: ${u}
|
|
46
46
|
|
|
47
47
|
COMMIT DIFF:
|
|
48
|
-
${r}`});return l?{id:c.id,verdict:l.verdict,reason:l.reason}:null}),s=[],a={};for(let c of i)c&&c.verdict==="stale"&&(s.push(c.id),c.reason&&(a[c.id]=c.reason));try{await A(`${
|
|
49
|
-
${t.new_string??""}`;s=i.match.contentPatterns.some(c=>
|
|
50
|
-
`).filter(Boolean);for(let t=e.length-1;t>=0;t--){let r=JSON.parse(e[t]),o=r.message??r;if((o.role??r.type)==="assistant"){let s=o.content,a=Array.isArray(s)?s.map(c=>c.text??"").join(" "):typeof s=="string"?s:"";if(a.trim())return a.trim().slice(0,300)}}}catch{}return""}function
|
|
48
|
+
${r}`});return l?{id:c.id,verdict:l.verdict,reason:l.reason}:null}),s=[],a={};for(let c of i)c&&c.verdict==="stale"&&(s.push(c.id),c.reason&&(a[c.id]=c.reason));try{await A(`${g}/api/prompt/commit-event`,4e3,{method:"POST",headers:_(),body:JSON.stringify({hash:t,repoFingerprint:n,staleIds:s,reasons:a})})}catch{}}var ct=new Set(["Edit","Write","MultiEdit","NotebookEdit"]);function lt(n){let e="";for(let t=0;t<n.length;t++){let r=n[t];r==="*"?n[t+1]==="*"?(e+=".*",t++,n[t+1]==="/"&&t++):e+="[^/]*":".+^${}()|[]\\".includes(r)?e+="\\"+r:r==="?"?e+=".":e+=r}return new RegExp("^"+e+"$")}function J(n,e){try{return n().test(e)}catch{return!1}}function ut(n,e,t){let r={deny:3,ask:2,warn:1,allow:0},o={decision:"allow",message:null};for(let i of n){if(!i||!i.match||!Array.isArray(i.match.tools)||!(i.match.tools.includes("*")||i.match.tools.includes(e)))continue;let s=!1;if(i.match.pathGlobs&&ct.has(e)){let a=t.file_path??t.path??"";s=i.match.pathGlobs.some(c=>J(()=>lt(c),a))}if(!s&&i.match.commandPatterns&&e==="Bash"){let a=t.command??"";s=i.match.commandPatterns.some(c=>J(()=>new RegExp(c),a))}if(!s&&i.match.contentPatterns){let a=`${t.content??""}
|
|
49
|
+
${t.new_string??""}`;s=i.match.contentPatterns.some(c=>J(()=>new RegExp(c),a))}s&&r[i.action]>r[o.decision]&&(o.decision=i.action,o.message=i.message)}return o}var ye="{}";function pt(n){let{decision:e,message:t}=n;return e==="deny"||e==="ask"?{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:e,...t?{permissionDecisionReason:t}:{}}}:e==="warn"&&t?{hookSpecificOutput:{hookEventName:"PreToolUse",additionalContext:t}}:{}}function dt(n,e){let t=[];try{if(n){let s=JSON.parse(h(n,"utf8"));Array.isArray(s)&&(t=s)}}catch{t=[]}let r="",o={};try{let s=JSON.parse(e);r=s.tool_name??"",o=s.tool_input??{}}catch{}let i=ut(t,r,o);process.stdout.write(JSON.stringify(pt(i)))}function E(){return new Promise(n=>{let e="";try{process.stdin.setEncoding("utf8"),process.stdin.on("data",t=>e+=t),process.stdin.on("end",()=>n(e)),process.stdin.on("error",()=>n(e)),setTimeout(()=>n(e),1500)}catch{n(e)}})}function ft(n){if(!n||!I(n))return"";try{let e=h(n,"utf8").trim().split(`
|
|
50
|
+
`).filter(Boolean);for(let t=e.length-1;t>=0;t--){let r=JSON.parse(e[t]),o=r.message??r;if((o.role??r.type)==="assistant"){let s=o.content,a=Array.isArray(s)?s.map(c=>c.text??"").join(" "):typeof s=="string"?s:"";if(a.trim())return a.trim().slice(0,300)}}}catch{}return""}function gt(n,e,t){if(!(!C(e??"")||m==="mock"||!S||!w||!R))try{let r=process.argv[1];if(!r)return;let o=Buffer.from(t,"utf8").toString("base64");L(process.execPath,[r,"notify-bg",n,e??"",o],{detached:!0,stdio:"ignore"}).unref()}catch{}}async function mt(n,e,t){if(!C(e??"")||m==="mock"||!S||!w||!R)return;let r={};try{r=JSON.parse(t)}catch{}let o=Je(process.cwd()),i=n==="attention",s=i?r.message||"Claude needs your input":ft(r.transcript_path)||"Session finished",a=`[${o}] ${s}`.slice(0,500),c=e||process.env.SUPERCLAWD_SESSION_ID||"",u={type:i?"attention_needed":"completion",summary:a,x_session_request_id:c},l=()=>A(`${g}/api/prompt/notify-checkpoint`,4e3,{method:"POST",headers:{..._(),"x-session-request-id":c},body:JSON.stringify(u)});try{let d=await l();d.status===404&&c&&(await A(`${g}/api/prompt/inspector`,4e3,{method:"POST",headers:{..._(),"x-session-request-id":c},body:JSON.stringify({ide:!0,platform:"claude-code",llm_model:"claude",x_session_request_id:c,notify_on_checkpoint:!0,enable_session_files:!1})}).catch(()=>{}),d=await l())}catch{}}async function A(n,e,t){let r=new AbortController,o=setTimeout(()=>r.abort(),e);try{return await fetch(n,{...t,signal:r.signal})}finally{clearTimeout(o)}}function pe(n,e,t){try{L(n,e,{detached:!0,stdio:"ignore",env:t??process.env}).unref()}catch{}}function de(n,e,t){if(process.platform==="darwin"){let r=t?`display notification m with title ${j(n)} subtitle ${j(t)} sound name "Glass"`:`display notification m with title ${j(n)} sound name "Glass"`;pe("osascript",["-e","on run {m}","-e",r,"-e","end run",e]);return}process.platform!=="win32"&&pe("notify-send",[n,e])}function j(n){return`"${n.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}function ht(n,e,t){if(C(t??"")){if(n==="attention"){let r="";try{r=JSON.parse(e).message??""}catch{}if(r.includes("waiting for your input"))return;de("Claude Code",r||"Claude needs you","Needs you");return}de("Claude Code","Done \u2014 your turn.")}}function yt(n,e){let t=Number(process.env.SUPERCLAWD_REMIND_EVERY??8);if(!Number.isFinite(t)||t<=0||!n||!e)return;let r=0;try{r=parseInt(h(e,"utf8").trim(),10)||0}catch{}r+=1;try{G(e,String(r))}catch{}if(r%t!==0)return;let o="";try{o=h(n,"utf8")}catch{return}o&&process.stdout.write(JSON.stringify({hookSpecificOutput:{hookEventName:"PostToolUse",additionalContext:o}}))}var Et=5;async function vt(n,e){if(m==="mock"||!S||!w||!R)return;let t="",r=n==="prompt"?"UserPromptSubmit":"PreToolUse";try{let o=JSON.parse(e||"{}");if(n==="prompt")t=String(o.prompt??"");else{let i=o.tool_input??{};t=String(i.file_path??i.path??"")}}catch{return}if(t=t.trim(),!(t.length<4))try{let o=new URLSearchParams({query:t.slice(0,500)}),i=process.env.SUPERCLAWD_REPO_FINGERPRINT;i&&o.set("repoFingerprint",i);let s=await D(`${g}/api/prompt/memories/search?${o.toString()}`,n==="prompt"?2500:1500);if(!s.ok)return;let c=((await s.json()).memories??[]).slice(0,Et);if(c.length===0)return;let u=c.map(d=>` [${d.scope}] ${d.id} ${(d.title??"").trim()}`).join(`
|
|
51
51
|
`),l=n==="prompt"?"RELEVANT PROJECT MEMORIES for this request (titles only \u2014 fetch the full text with get_memories([id]) before relying on one):":"PROJECT MEMORIES that may relate to this file (titles only \u2014 fetch with get_memories([id]) if relevant):";process.stdout.write(JSON.stringify({hookSpecificOutput:{hookEventName:r,additionalContext:`${l}
|
|
52
|
-
${u}`}}))}catch{}}var
|
|
53
|
-
`)}catch{}}function
|
|
54
|
-
`).filter(Boolean)}catch{return""}let r=[];for(let i of t){let s;try{s=JSON.parse(i)}catch{continue}let a=s.message??s,c=a.role??s.type;if(c!=="user"&&c!=="assistant")continue;let u=a.content;if(typeof u=="string"){u.trim()&&r.push(`${c.toUpperCase()}: ${u.trim()}`);continue}if(Array.isArray(u)){for(let l of u)if(l?.type==="text"&&typeof l.text=="string"&&l.text.trim())r.push(`${c.toUpperCase()}: ${l.text.trim()}`);else if(l?.type==="tool_use"){let
|
|
52
|
+
${u}`}}))}catch{}}var St=3e4,Ee=process.env.SUPERCLAWD_CAPTURE_MODEL||P;function p(n,e){if(process.env.SUPERCLAWD_DEBUG==="1")try{let t=x("date -u +%Y-%m-%dT%H:%M:%SZ",{encoding:"utf8"}).trim();We(`${je()}/.superclawd/capture-debug.log`,JSON.stringify({ts:t,stage:n,...e})+`
|
|
53
|
+
`)}catch{}}function K(n,e=St){if(!n||!I(n))return"";let t;try{t=h(n,"utf8").trim().split(`
|
|
54
|
+
`).filter(Boolean)}catch{return""}let r=[];for(let i of t){let s;try{s=JSON.parse(i)}catch{continue}let a=s.message??s,c=a.role??s.type;if(c!=="user"&&c!=="assistant")continue;let u=a.content;if(typeof u=="string"){u.trim()&&r.push(`${c.toUpperCase()}: ${u.trim()}`);continue}if(Array.isArray(u)){for(let l of u)if(l?.type==="text"&&typeof l.text=="string"&&l.text.trim())r.push(`${c.toUpperCase()}: ${l.text.trim()}`);else if(l?.type==="tool_use"){let d=JSON.stringify(l.input??{}).slice(0,200);r.push(`[tool ${l.name}: ${d}]`)}else if(l?.type==="tool_result"){let d=l.content,f=typeof d=="string"?d:Array.isArray(d)?d.map(v=>v?.text??"").join(" "):"";f.trim()&&r.push(`[result: ${f.trim().slice(0,200)}]`)}}}let o=r.join(`
|
|
55
55
|
`);return o.length>e&&(o=`\u2026
|
|
56
|
-
`+o.slice(o.length-e)),o}function
|
|
57
|
-
`):e}async function
|
|
58
|
-
${
|
|
56
|
+
`+o.slice(o.length-e)),o}function X(n){let e=U()?.credentials??{},t=n?$(k(n)):null;return{keyId:process.env.SUPERCLAWD_MCP_KEY||e.keyId||"",secret:process.env.SUPERCLAWD_MCP_SECRET||e.secret||"",workspace:process.env.SUPERCLAWD_MCP_WORKSPACE||t?.workspace||e.workspace||""}}function V(n){return{"content-type":"application/json","x-mcp-key-id":n.keyId,"x-mcp-secret":n.secret,"x-workspace-slug":n.workspace,"x-request-id":ge()}}async function H(n,e,t){try{let r=n==="private"?`${g}/api/prompt/memories?scope=private`:`${g}/api/prompt/memories?scope=${n}&scopeKey=${encodeURIComponent(e)}`,o=await A(r,4e3,{headers:V(t)});return o.ok?((await o.json().catch(()=>({}))).memories??[]).filter(s=>s.id).map(s=>({id:String(s.id),body:(s.body??s.title??"").trim(),locked:s.lockedAt!=null})):[]}catch{return[]}}function N(n,e){return n.length?n.map(t=>`[${t.id}]${t.locked?" [LOCKED]":""} ${t.body}`).join(`
|
|
57
|
+
`):e}async function ve(n,e,t,r){for(let o of n){let i=t(o.scope);if(!i){p(`${r}-skip-unrouted`,{scope:o.scope??null});continue}let s=(o.body||"").trim();if(o.op==="create"){if(s.length<12)continue;try{let a={scope:i.scope,content:s,learnedAgainst:i.learnedAgainst};i.scopeKey!=null&&(a.scopeKey=i.scopeKey),o.title&&o.title.trim()&&(a.title=o.title.trim());let c=await A(`${g}/api/prompt/memories`,8e3,{method:"POST",headers:V(e),body:JSON.stringify(a)});p(`${r}-create`,{scope:i.scope,status:c.status,ok:c.ok})}catch(a){p(`${r}-create-error`,{error:String(a)})}}else if(o.op==="update"&&o.id){if(!i.allowUpdate){p(`${r}-skip-update`,{scope:i.scope,id:o.id});continue}if(s.length<12)continue;try{let a=await A(`${g}/api/prompt/memories/${encodeURIComponent(o.id)}`,8e3,{method:"PUT",headers:V(e),body:JSON.stringify({content:s,learnedAgainst:i.learnedAgainst,...o.title&&o.title.trim()?{title:o.title.trim()}:{}})});p(`${r}-update`,{id:o.id,status:a.status,ok:a.ok})}catch(a){p(`${r}-update-error`,{error:String(a)})}}}}var wt=18e4;function Rt(n){if(!n)return null;let e;try{e=k(n)}catch{return null}let t=`${e}/capture.lock`;try{return G(t,String(process.pid),{flag:"wx"}),t}catch{try{return Date.now()-q(t).mtimeMs<wt?null:(G(t,String(process.pid)),t)}catch{return null}}}function At(n){if(n)try{Fe(n)}catch{}}function bt(n,e){let t=process.env.SUPERCLAWD_REPO_FINGERPRINT||"";if(process.env.SUPERCLAWD_POLICY_JUDGE==="1")return;let r=X(e);if(m==="mock"||!r.keyId||!r.secret||!r.workspace||!t){p("detached-skip",{backend:m,hasKey:!!r.keyId,hasSecret:!!r.secret,hasWorkspace:!!r.workspace,hasFp:!!t,launchId:e});return}try{let o=process.argv[1];if(!o)return;let i=Buffer.from(n,"utf8").toString("base64"),s=L(process.execPath,[o,"capture-bg",i,e],{detached:!0,stdio:"ignore"});s.unref(),p("detached-spawn",{pid:s.pid??null,launchId:e})}catch(o){p("detached-error",{error:String(o)})}}async function Ot(n,e){let t=process.env.SUPERCLAWD_REPO_FINGERPRINT||"",r=X(e);if(p("bg-start",{hasFp:!!t,hasKey:!!r.keyId,hasWorkspace:!!r.workspace}),m==="mock"||!r.keyId||!r.secret||!r.workspace||!t)return;if(!O()){p("bg-no-claude");return}let o={};try{o=JSON.parse(n)}catch{p("bg-bad-payload");return}let i=K(o.transcript_path);if(!i){p("bg-no-digest",{transcript:o.transcript_path??null});return}let s=(i.match(/\n?\[tool /g)||[]).length,a=Number(process.env.SUPERCLAWD_CAPTURE_MIN_TOOLS??3),c=process.env.SUPERCLAWD_PRIVATE_MEMORY==="1",u=Number(process.env.SUPERCLAWD_PRIVATE_MIN_DIGEST??280),l=Number.isFinite(a)&&a>0&&s<a,d=c&&i.length>=u;if(p("bg-digest",{digestLen:i.length,toolUses:s,minTools:a,privateOn:c}),l&&!d)return;let f=Rt(e);if(!f){p("bg-locked");return}let v=y=>{try{return y&&I(y)?q(y).mtimeMs:0}catch{return 0}},Se=v(o.transcript_path);try{if(await fe(t,r,i,c),v(o.transcript_path)>Se){let y=K(o.transcript_path),we=(y.match(/\n?\[tool /g)||[]).length,Re=Number.isFinite(a)&&a>0&&we<a,Ae=c&&y.length>=u,z=!!y&&!(Re&&!Ae);p("bg-rerun",{digestLen:y.length,willRun:z}),z&&await fe(t,r,y,c)}}finally{At(f)}}async function fe(n,e,t,r){let o=process.env.SUPERCLAWD_REPO_MEMORY!=="0",i=[];try{let l=x("git rev-parse HEAD",{cwd:process.cwd(),encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim();l&&(i=[l])}catch{}let s=await H("repo",n,e),a=r?await H("private","",e):[];p("bg-existing",{repo:s.length,private:a.length});let c=await F({system:r?Q:Z,model:Ee,user:r?`ALREADY-SAVED REPO MEMORIES (reconcile against these; ids in brackets):
|
|
58
|
+
${N(s,"NONE \u2014 this repo has no saved memories yet; future sessions start with zero knowledge of it.")}
|
|
59
59
|
|
|
60
60
|
ALREADY-SAVED PRIVATE MEMORIES for this user (create only genuinely new ones; never update):
|
|
61
|
-
${
|
|
61
|
+
${N(a,"NONE \u2014 this user has no saved private preferences yet.")}
|
|
62
62
|
|
|
63
63
|
FINISHED SESSION (condensed transcript; most recent at the end) \u2014 emit scope-tagged ops to keep both sets accurate & minimal:
|
|
64
64
|
${t}`:`ALREADY-SAVED MEMORIES FOR THIS REPO (reconcile against these; ids in brackets):
|
|
65
|
-
${
|
|
65
|
+
${N(s,"NONE \u2014 this repo has no saved memories yet; future sessions start with zero knowledge of it.")}
|
|
66
66
|
|
|
67
67
|
FINISHED SESSION (condensed transcript; most recent at the end) \u2014 emit ops to keep the repo's memory accurate & minimal:
|
|
68
|
-
${t}`,timeoutMs:6e4,onRaw:process.env.SUPERCLAWD_DEBUG==="1"?l=>
|
|
69
|
-
${
|
|
68
|
+
${t}`,timeoutMs:6e4,onRaw:process.env.SUPERCLAWD_DEBUG==="1"?l=>p("bg-judge-raw",{raw:l.slice(0,2e3)}):void 0}),u=Array.isArray(c?.ops)?c.ops:[];p("bg-ops",{ops:u.map(l=>`${l.scope??"repo"}:${l.op}`)}),await ve(u,e,l=>r&&l==="private"?{scope:"private",scopeKey:null,learnedAgainst:[],allowUpdate:!1}:o?{scope:"repo",scopeKey:n,learnedAgainst:i,allowUpdate:!0}:null,"bg")}var B=oe;function kt(n,e,t){if(process.env.SUPERCLAWD_POLICY_JUDGE==="1"||m==="mock")return;let r="";try{r=JSON.parse(n).agent_type??""}catch{return}if(p("agent-detached",{agentType:r}),!!r.startsWith(B))try{let o=process.argv[1];if(!o)return;let i=Buffer.from(n,"utf8").toString("base64"),s=L(process.execPath,[o,"capture-agent-bg",i,e,t],{detached:!0,stdio:"ignore"});s.unref(),p("agent-detached-spawn",{pid:s.pid??null})}catch(o){p("agent-detached-error",{error:String(o)})}}async function Ct(n,e,t){let r;try{r=JSON.parse(n)}catch{return}let o=r.agent_type??"";if(!o.startsWith(B))return;let i=o.slice(B.length),s="";try{let f=JSON.parse(h(e,"utf8"));typeof f[i]=="string"&&(s=f[i])}catch{}if(p("agent-bg-start",{slug:i,hasAgentId:!!s}),!s)return;let a=X(t);if(m==="mock"||!a.keyId||!a.secret||!a.workspace)return;if(!O()){p("agent-bg-no-claude");return}let c=K(r.agent_transcript_path||r.transcript_path);if(p("agent-bg-digest",{digestLen:c.length}),c.length<200)return;let u=await H("agent",s,a);p("agent-bg-existing",{count:u.length});let l=await F({system:ee,model:Ee,user:`ALREADY-SAVED LESSONS FOR THIS AGENT (reconcile against these; ids in brackets):
|
|
69
|
+
${N(u,"NONE \u2014 this agent has no saved lessons yet; it starts each run with only its base prompt.")}
|
|
70
70
|
|
|
71
71
|
FINISHED AGENT RUN (condensed transcript; most recent at the end) \u2014 emit ops to keep the agent's lessons accurate & minimal:
|
|
72
|
-
${c}`,timeoutMs:6e4,onRaw:process.env.SUPERCLAWD_DEBUG==="1"?f=>
|
|
72
|
+
${c}`,timeoutMs:6e4,onRaw:process.env.SUPERCLAWD_DEBUG==="1"?f=>p("agent-bg-judge-raw",{raw:f.slice(0,2e3)}):void 0}),d=Array.isArray(l?.ops)?l.ops:[];p("agent-bg-ops",{ops:d.map(f=>f.op)}),await ve(d,a,()=>({scope:"agent",scopeKey:s,learnedAgainst:[],allowUpdate:!0}),"agent-bg")}async function Pt(){let n=process.argv[2];if(n==="gate")return await E(),Ve();if(n==="guardrails"){let e=process.argv[3],t=await E();return dt(e,t)}if(n==="policy"){let e=process.argv[3],t=await E();return st(e,t)}if(n==="report-commit")return at();if(n==="notify"){let e=process.argv[3],t=process.argv[4],r=await E();gt(e,t,r);return}if(n==="notify-bg"){let e=process.argv[3],t=process.argv[4]||void 0,r=Buffer.from(process.argv[5]||"","base64").toString("utf8");return mt(e,t,r)}if(n==="notify-local"){let e=process.argv[3],t=process.argv[4]||void 0,r=await E();ht(e,r,t);return}if(n==="retrieve"){let e=process.argv[3]==="file"?"file":"prompt",t=await E();return vt(e,t)}if(n==="remind"){yt(process.argv[3],process.argv[4]);return}if(n==="capture-agent"){let e=process.argv[3]||"",t=process.argv[4]||"",r=await E();kt(r,e,t);return}if(n==="capture-agent-bg"){let e=Buffer.from(process.argv[3]||"","base64").toString("utf8"),t=process.argv[4]||"",r=process.argv[5]||"";await Ct(e,t,r);return}if(n==="capture"){let e=process.argv[3]||"",t=await E();bt(t,e);return}if(n==="capture-bg"){let e=Buffer.from(process.argv[3]||"","base64").toString("utf8"),t=process.argv[4]||"";await Ot(e,t);return}return await E(),Ke(process.argv[3],process.argv[4]||"SessionStart")}var Nt=new Set(["gate","guardrails","policy","report-commit","notify","notify-bg","notify-local","remind","retrieve","capture","capture-bg","capture-agent","capture-agent-bg"]),_t=!!process.argv[1]&&import.meta.url===Ge(process.argv[1]).href;_t&&Pt().catch(()=>{let n=process.argv[2];Nt.has(n)||process.stdout.write(M(process.argv[4]||"SessionStart",""))});export{ye as NO_DECISION,ut as evaluate,pt as guardrailDecision,vt as retrieve};
|