psyclaw 0.28.3 → 0.29.2

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 (66) hide show
  1. package/README.md +12 -11
  2. package/agents/recommended/catalog.json +2 -2
  3. package/dist/src/adapters/pi/extension.js +310 -256
  4. package/dist/src/adapters/pi/extension.js.map +1 -1
  5. package/dist/src/analysis/hooks.js +1 -1
  6. package/dist/src/analysis/hooks.js.map +1 -1
  7. package/dist/src/analysis/plan.d.ts +82 -0
  8. package/dist/src/analysis/plan.js +246 -0
  9. package/dist/src/analysis/plan.js.map +1 -0
  10. package/dist/src/analysis/stats-router.d.ts +13 -0
  11. package/dist/src/analysis/stats-router.js +44 -0
  12. package/dist/src/analysis/stats-router.js.map +1 -0
  13. package/dist/src/ars/academic-router.d.ts +33 -0
  14. package/dist/src/ars/academic-router.js +204 -0
  15. package/dist/src/ars/academic-router.js.map +1 -0
  16. package/dist/src/ars/doctor.d.ts +27 -0
  17. package/dist/src/ars/doctor.js +121 -0
  18. package/dist/src/ars/doctor.js.map +1 -0
  19. package/dist/src/ars/mode-editor.d.ts +14 -7
  20. package/dist/src/ars/mode-editor.js +39 -23
  21. package/dist/src/ars/mode-editor.js.map +1 -1
  22. package/dist/src/ars/profile.d.ts +10 -0
  23. package/dist/src/ars/profile.js +15 -2
  24. package/dist/src/ars/profile.js.map +1 -1
  25. package/dist/src/branding.js +15 -16
  26. package/dist/src/branding.js.map +1 -1
  27. package/dist/src/cli.js +1 -8
  28. package/dist/src/cli.js.map +1 -1
  29. package/dist/src/index.d.ts +6 -1
  30. package/dist/src/index.js +6 -1
  31. package/dist/src/index.js.map +1 -1
  32. package/dist/src/panel/server.js +1 -1
  33. package/dist/src/panel/server.js.map +1 -1
  34. package/dist/src/project/approvals.d.ts +4 -3
  35. package/dist/src/project/approvals.js +4 -3
  36. package/dist/src/project/approvals.js.map +1 -1
  37. package/dist/src/project/bootstrap.d.ts +7 -2
  38. package/dist/src/project/bootstrap.js +14 -13
  39. package/dist/src/project/bootstrap.js.map +1 -1
  40. package/dist/src/project/paths.d.ts +10 -0
  41. package/dist/src/project/paths.js +20 -3
  42. package/dist/src/project/paths.js.map +1 -1
  43. package/dist/src/project/workspace.d.ts +14 -0
  44. package/dist/src/project/workspace.js +82 -0
  45. package/dist/src/project/workspace.js.map +1 -0
  46. package/dist/src/session/modes.d.ts +10 -0
  47. package/dist/src/session/modes.js +57 -0
  48. package/dist/src/session/modes.js.map +1 -0
  49. package/dist/src/skills/recommended.js +1 -1
  50. package/dist/src/skills/recommended.js.map +1 -1
  51. package/dist/src/style/cli-ui.js +3 -3
  52. package/dist/src/style/cli-ui.js.map +1 -1
  53. package/dist/src/verify/checklist.d.ts +20 -0
  54. package/dist/src/verify/checklist.js +71 -0
  55. package/dist/src/verify/checklist.js.map +1 -0
  56. package/package.json +2 -1
  57. package/scripts/rebrand-pi.mjs +2 -2
  58. package/skills/core/academic-grill/SKILL.md +1 -1
  59. package/skills/core/analysis-plan/SKILL.md +29 -0
  60. package/skills/core/manifest.json +3 -3
  61. package/vendor/ars/pi/wrapper.js +14 -5
  62. package/vendor/ars/pi/wrapper.test.mjs +10 -0
  63. package/dist/src/research/brief.d.ts +0 -11
  64. package/dist/src/research/brief.js +0 -81
  65. package/dist/src/research/brief.js.map +0 -1
  66. package/skills/core/research-brief/SKILL.md +0 -17
@@ -0,0 +1,71 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { atomicWriteFile } from "../project/jsonl.js";
3
+ import { assertSafeProjectPath } from "../project/paths.js";
4
+ export const VERIFY_CHECKLIST_SCHEMA = "psyclaw/verify-checklist/v1";
5
+ export const VERIFY_CHECKLIST_PATH = ".psyclaw/verify-checklist.json";
6
+ const DEFAULT_ITEMS = [
7
+ { id: "n", label: "样本量 / N" },
8
+ { id: "primary-effect", label: "主效应 / 主要结果" },
9
+ { id: "table-text", label: "表与正文一致" },
10
+ { id: "method-match", label: "方法与实际分析一致" },
11
+ { id: "key-claim", label: "关键主张有结果支撑" },
12
+ ];
13
+ export function defaultVerifyChecklist(now = new Date().toISOString()) {
14
+ return {
15
+ schemaVersion: VERIFY_CHECKLIST_SCHEMA,
16
+ updatedAt: now,
17
+ items: DEFAULT_ITEMS.map((item) => ({ ...item, status: "unverified" })),
18
+ };
19
+ }
20
+ export async function loadVerifyChecklist(root) {
21
+ const path = await assertSafeProjectPath(root, VERIFY_CHECKLIST_PATH);
22
+ try {
23
+ const parsed = JSON.parse(await readFile(path, "utf8"));
24
+ if (parsed.schemaVersion !== VERIFY_CHECKLIST_SCHEMA || !Array.isArray(parsed.items)) {
25
+ return defaultVerifyChecklist();
26
+ }
27
+ return {
28
+ schemaVersion: VERIFY_CHECKLIST_SCHEMA,
29
+ updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : new Date().toISOString(),
30
+ items: parsed.items.filter((item) => Boolean(item && typeof item.id === "string" && typeof item.label === "string" &&
31
+ (item.status === "unverified" || item.status === "verified" || item.status === "flagged"))),
32
+ };
33
+ }
34
+ catch {
35
+ return defaultVerifyChecklist();
36
+ }
37
+ }
38
+ export async function saveVerifyChecklist(root, checklist) {
39
+ const path = await assertSafeProjectPath(root, VERIFY_CHECKLIST_PATH);
40
+ await atomicWriteFile(path, `${JSON.stringify(checklist, null, 2)}\n`);
41
+ }
42
+ export async function markVerifyItem(root, id, status, notes) {
43
+ const checklist = await loadVerifyChecklist(root);
44
+ const now = new Date().toISOString();
45
+ const existing = checklist.items.find((item) => item.id === id);
46
+ if (existing) {
47
+ existing.status = status;
48
+ existing.updatedAt = now;
49
+ if (notes !== undefined)
50
+ existing.notes = notes;
51
+ }
52
+ else {
53
+ const item = { id, label: id, status, updatedAt: now };
54
+ if (notes !== undefined)
55
+ item.notes = notes;
56
+ checklist.items.push(item);
57
+ }
58
+ checklist.updatedAt = now;
59
+ await saveVerifyChecklist(root, checklist);
60
+ return checklist;
61
+ }
62
+ export function formatVerifyChecklist(checklist) {
63
+ const lines = ["核查清单(AI 语义核查 + 人确认;非 SHA 学术过关)", `更新:${checklist.updatedAt}`];
64
+ for (const item of checklist.items) {
65
+ const mark = item.status === "verified" ? "[x]" : item.status === "flagged" ? "[!]" : "[ ]";
66
+ lines.push(`${mark} ${item.id}: ${item.label}${item.notes ? ` — ${item.notes}` : ""}`);
67
+ }
68
+ lines.push("用法:/verify list | /verify <id> verified|unverified|flagged [备注]");
69
+ return lines.join("\n");
70
+ }
71
+ //# sourceMappingURL=checklist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checklist.js","sourceRoot":"","sources":["../../../src/verify/checklist.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "psyclaw",
3
- "version": "0.28.3",
3
+ "version": "0.29.2",
4
4
  "description": "A standalone, evidence-grounded social-science research agent with research contracts, evidence gates, and recoverable workflows",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -73,6 +73,7 @@
73
73
  "test:watch": "vitest",
74
74
  "eval": "tsx evals/harness.ts",
75
75
  "eval:modules": "tsx evals/modules.ts",
76
+ "eval:academic-route": "tsx evals/academic-soft-route/harness.ts",
76
77
  "rebrand": "node scripts/rebrand-pi.mjs",
77
78
  "check:branding": "node scripts/check-branding.mjs",
78
79
  "release:push": "node scripts/release-push.mjs",
@@ -165,7 +165,7 @@ const logo = [
165
165
  "",
166
166
  ].join("\\n");`;
167
167
 
168
- const GRAD_CORE_SKILLS = "\\x1b[1m\\x1b[38;2;56;189;248m✦ 核心证据链:\\x1b[0m \\x1b[1m\\x1b[38;2;56;189;248mresearch-intake\\x1b[0m \\x1b[38;2;99;102;241m➔\\x1b[0m \\x1b[1m\\x1b[38;2;129;140;248mevidence-capture\\x1b[0m \\x1b[38;2;168;85;247m➔\\x1b[0m \\x1b[1m\\x1b[38;2;168;85;247mcitation-audit\\x1b[0m \\x1b[38;2;236;72;153m➔\\x1b[0m \\x1b[1m\\x1b[38;2;45;212;191mresearch-brief\\x1b[0m";
168
+ const GRAD_CORE_SKILLS = "\\x1b[1m\\x1b[38;2;56;189;248m✦ 核心证据链:\\x1b[0m \\x1b[1m\\x1b[38;2;56;189;248mresearch-intake\\x1b[0m \\x1b[38;2;99;102;241m➔\\x1b[0m \\x1b[1m\\x1b[38;2;129;140;248mevidence-capture\\x1b[0m \\x1b[38;2;168;85;247m➔\\x1b[0m \\x1b[1m\\x1b[38;2;168;85;247mcitation-audit\\x1b[0m";
169
169
 
170
170
  const PSYCLAW_SKILLS_FORMATTER = `const skills = skillsResult.skills;
171
171
  if (skills.length > 0) {
@@ -174,7 +174,7 @@ const PSYCLAW_SKILLS_FORMATTER = `const skills = skillsResult.skills;
174
174
  formatPath: (item) => this.formatDisplayPath(item.path),
175
175
  formatPackagePath: (item) => this.getShortPath(item.path, item.sourceInfo),
176
176
  });
177
- const CORE_PIPELINE = ["research-intake", "evidence-capture", "citation-audit", "research-brief"];
177
+ const CORE_PIPELINE = ["research-intake", "evidence-capture", "citation-audit"];
178
178
  const availableCore = CORE_PIPELINE.filter((name) => skills.some((s) => s.name === name));
179
179
  const otherSkills = skills.filter((s) => !CORE_PIPELINE.includes(s.name)).map((s) => s.name);
180
180
  const skillCompactList = \` ${GRAD_CORE_SKILLS}\\n\${theme.fg("dim", \` ⟡ 生态扩展 (\${otherSkills.length}): \${otherSkills.slice(0, 10).join(", ")}\${otherSkills.length > 10 ? " ... (按 Ctrl+O 展开全部)" : ""}\`)}\`;
@@ -17,7 +17,7 @@ When the user provides a dataset or topic without a mature research question, be
17
17
  - Resolve upstream decisions before downstream ones. Do not ask about an analysis technique while the construct, estimand, comparison, or data-generating process is still unclear.
18
18
  - If the answer can be established from files, project state, registered evidence, code, or prior conversation, inspect those sources instead of asking the user.
19
19
  - Enter a researcher decision only when at least two substantively defensible options remain after checking the available evidence and established methods, and the choice would change the research question, sample treatment, operationalization, estimand, analysis method, or interpretation. Record what evidence and methods were checked, explain why they cannot resolve the disagreement, and state the options, evidence, consequences, and your recommendation.
20
- - Do not ask the researcher to decide software installation, dependency repair, file formatting, script debugging, reproducibility metadata, citation formatting, or a reporting omission that the agent can repair. Repair these directly inside an active `/run`, or report a concrete technical limitation without treating it as a research decision.
20
+ - Do not ask the researcher to decide software installation, dependency repair, file formatting, script debugging, reproducibility metadata, citation formatting, or a reporting omission that the agent can repair. Repair these directly after `/init`, or report a concrete technical limitation without treating it as a research decision.
21
21
  - A dataset supplied for analysis is exploratory by default unless the user says that hypotheses and analyses were fixed before seeing it. Do not lead with a preregistration question, do not ask for a preregistration URL, and do not imply that exploratory work is methodologically inferior. For explicitly confirmatory work, ask what was specified in advance only when that distinction affects analysis or interpretation.
22
22
  - Use researcher-facing language. Keep internal terms such as Claim, Evidence, ledger, gate, audit, blocked, receipt, and dependency out of ordinary questions and proposed prose.
23
23
  - Use the user's latest answer to choose the next unresolved branch. Do not dump a static questionnaire.
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: analysis-plan
3
+ description: Soft-takeover stats planning in analysis mode — light EDA, clarifying questions, structured proposal, soft confirm, review, then run now or later via local scripts (MCP only when needed).
4
+ license: MIT
5
+ ---
6
+
7
+ # Analysis Plan
8
+
9
+ Use this skill only in **analysis** mode. Do not start academic/ARS writing from here.
10
+
11
+ ## Stages
12
+
13
+ 1. **Clarify + light EDA** — Inspect available data under `data/clean` (or documented paths). Write a short profile (shape, dtypes, missingness, key ranges) once; do not spam ad-hoc probes. Ask only high-value clarifying questions that change the estimand, sample treatment, or method family.
14
+ 2. **Propose** — Produce a structured plan: goal, confirmatory vs exploratory, primary outcome, primary analysis, alternatives considered, missing-data / multiplicity / exclusion notes, and proposed script layout under `analysis/scripts/`.
15
+ 3. **Soft confirm** — Present the proposal clearly and ask the researcher to confirm with `/plan confirm <method>` (or reject). Soft confirm is not an ARS checkpoint and not a hard `awaiting-human` safety gate.
16
+ 4. **Review** — Run `/plan review` (or ask the user to). Fix warn/block findings before execution.
17
+ 5. **Execute** — `/plan run` (now) or `/plan defer` (later). Default backend: **local reproducible scripts** using mature libraries (pandas / pingouin / statsmodels / scipy, or R equivalents). Use MCP only for special backends (SPSS / Mplus / MNE / Stata) or when the user explicitly asks.
18
+ 6. **Handoff** — After results exist, update `analysis/HANDOFF.md` (`/plan handoff`) before the user switches to academic mode. Academic mode must consume the handoff and must not re-choose primary tests.
19
+
20
+ ## Persistence
21
+
22
+ Keep durable state in `analysis/plans/` via `/plan` commands (`new`, `status`, `confirm`, `review`, `run`, `defer`, `handoff`). Prefer thin entrypoints (`run_all.py`) and reviewable modules; never invent numerical results.
23
+
24
+ ## Boundaries
25
+
26
+ - Never overwrite `data/raw`.
27
+ - Never implement novel statistical algorithms inside PsyClaw core; call libraries or trusted MCP.
28
+ - Do not merge this plan with ARS stage planning.
29
+ - Label unverified claims; use `/verify` for human marks on critical fields.
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "schemaVersion": "psyclaw/skill-pack/v1",
3
3
  "id": "psyclaw-core",
4
- "version": "0.2.0",
4
+ "version": "0.3.0",
5
5
  "skills": [
6
6
  "academic-grill",
7
7
  "research-intake",
8
8
  "evidence-capture",
9
9
  "citation-audit",
10
- "research-brief"
10
+ "analysis-plan"
11
11
  ],
12
- "enabledByDefault": ["academic-grill", "research-intake", "evidence-capture", "citation-audit", "research-brief"],
12
+ "enabledByDefault": ["academic-grill", "research-intake", "evidence-capture", "citation-audit", "analysis-plan"],
13
13
  "source": {"kind": "workspace", "ref": "initial-mvp"},
14
14
  "license": {"spdx": "MIT", "evidenceRef": "../../LICENSE"},
15
15
  "dependencyStatus": "ready"
@@ -173,29 +173,38 @@ export default function (pi) {
173
173
  const python = await probe(pi, "python3", ["--version"]);
174
174
  const pyyaml = await probe(pi, "python3", ["-c", "import yaml; print(f'PyYAML {yaml.__version__}')"]);
175
175
  const pandoc = await probe(pi, "pandoc", ["--version"]);
176
- const tectonic = await probe(pi, "tectonic", ["--version"]);
177
176
  const sandbox = pi.getCommands().some((command) => command.name === "sandbox")
178
177
  ? `detected; allow read access to ${repoRoot} when running outside the checkout`
179
178
  : "not detected";
180
179
  const format = (matches) => matches.length > 0 ? matches.join(", ") : "none; sequential/degraded mode";
180
+ const psyclawOrch = [
181
+ ...uniqueMatches(candidates, /psyclaw_ars_multi_agent|ars multi-agent|parallel-agent/i),
182
+ ...commands.filter((item) => /agents|create-subagent/i.test(item.search)).map((item) => item.label),
183
+ ];
184
+ const orchestrationLine = psyclawOrch.length > 0
185
+ ? psyclawOrch.join(", ")
186
+ : format(orchestration);
181
187
  const report = [
182
188
  "ARS Pi doctor",
183
189
  `Repository: ${repoRoot}`,
184
- `Orchestration: ${format(orchestration)}`,
190
+ `Orchestration: ${orchestrationLine}`,
185
191
  `Web retrieval: ${format(web)}`,
186
192
  `Python: ${python}`,
187
193
  `PyYAML: ${pyyaml}`,
188
194
  `Pandoc: ${pandoc}`,
189
- `Tectonic: ${tectonic}`,
195
+ "PDF engine: not preflighted; install on demand when the user asks to export PDF (psyclaw_ensure_pdf_engine)",
190
196
  `Sandbox: ${sandbox}`,
191
- "Claude hooks: unavailable in Pi; write-scope enforcement remains prompt-level",
197
+ "Hooks: PsyClaw analysis hooks + tool_call gates after /init; Claude Code PreToolUse hooks.json is not loaded by Pi",
192
198
  ].join("\n");
193
199
 
194
200
  pi.sendMessage({ customType: "ars-pi-doctor", content: report, display: true });
195
201
  },
196
202
  });
197
203
 
198
- pi.on("before_agent_start", (event) => {
204
+ pi.on("before_agent_start", (event, ctx) => {
205
+ // Keep in-memory flag aligned with session entries written by PsyClaw Shift+Tab
206
+ // (silent appendEntry) or prior /ars-pi-start|/ars-pi-stop handlers.
207
+ if (ctx?.sessionManager) restoreArsState(ctx);
199
208
  if (!arsActive) return { systemPrompt: hideArsSkills(event.systemPrompt) };
200
209
  return { systemPrompt: `${event.systemPrompt}\n${compatibility}` };
201
210
  });
@@ -199,3 +199,13 @@ test("/ars-pi-start and /ars-pi-stop toggle automatic invocation", async () => {
199
199
  assert.equal(runBeforeAgentStart(harness).includes(location), false);
200
200
  }
201
201
  });
202
+
203
+ test("before_agent_start restores ARS state from session entries (silent Shift+Tab path)", () => {
204
+ const harness = createHarness();
205
+ harness.setBranch([{ type: "custom", customType: "ars-pi-state", data: { active: true } }]);
206
+ const systemPrompt = harness.handlers.get("before_agent_start")(
207
+ { systemPrompt: baseSystemPrompt },
208
+ harness.sessionContext,
209
+ )?.systemPrompt ?? baseSystemPrompt;
210
+ assert.equal(systemPrompt.includes(compatibilityMarker), true);
211
+ });
@@ -1,11 +0,0 @@
1
- import type { GateResult, Handoff } from "../core/contracts.js";
2
- export interface BriefResult {
3
- runId: string;
4
- verdict: "pass" | "blocked";
5
- gates: GateResult[];
6
- briefPath?: string;
7
- manifestPath: string;
8
- verdictPath: string;
9
- handoff: Handoff;
10
- }
11
- export declare function runOfflineBrief(root: string): Promise<BriefResult>;
@@ -1,81 +0,0 @@
1
- import { mkdir } from "node:fs/promises";
2
- import { join } from "node:path";
3
- import { randomUUID } from "node:crypto";
4
- import { checkEvidenceSufficiency } from "../core/evidence-policy.js";
5
- import { projectPaths } from "../project/paths.js";
6
- import { loadLedger, readProject } from "./ledger.js";
7
- import { writeHandoff } from "../project/bootstrap.js";
8
- import { atomicWriteFile } from "../project/jsonl.js";
9
- import { RunEventLog } from "../panel/events.js";
10
- export async function runOfflineBrief(root) {
11
- const paths = projectPaths(root);
12
- const runId = `run_${randomUUID().replaceAll("-", "")}`;
13
- const project = await readProject(root);
14
- const ledger = await loadLedger(root);
15
- const gates = checkEvidenceSufficiency({ ...ledger, paradigm: project.paradigm });
16
- const blocked = gates.filter((gate) => !gate.ok);
17
- const eventLog = new RunEventLog(root, runId);
18
- const eventAt = new Date().toISOString();
19
- await eventLog.append({ type: "planned", at: eventAt });
20
- for (const gate of gates)
21
- await eventLog.append({ type: "gate", at: eventAt, message: gate.reason });
22
- await eventLog.append({
23
- type: blocked.length === 0 ? "completed" : "blocked",
24
- at: eventAt,
25
- message: blocked.length === 0 ? "all evidence gates passed" : "evidence gates blocked",
26
- });
27
- const manifest = {
28
- schemaVersion: "psyclaw/brief-manifest/v1",
29
- runId,
30
- inputs: ledger.evidence.map((item) => ({ id: item.id, sha256: item.sha256, locator: item.source.locator })),
31
- claims: ledger.claims.map((claim) => ({ id: claim.id, status: claim.status, evidenceIds: claim.evidenceIds })),
32
- gates,
33
- generatedAt: new Date().toISOString(),
34
- };
35
- await mkdir(paths.manifests, { recursive: true });
36
- const manifestPath = join(paths.manifests, `${runId}.json`);
37
- await atomicWriteFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
38
- let briefPath;
39
- if (blocked.length === 0) {
40
- const goal = project.goal;
41
- const lines = [
42
- "# Research Brief",
43
- "",
44
- `Research goal: ${goal}`,
45
- "",
46
- "## Audited Claims",
47
- "",
48
- ...ledger.claims.map((claim) => `- ${claim.text} [${claim.status}]`),
49
- "",
50
- "Evidence and limitations are recorded in the manifest and ledger.",
51
- "",
52
- ];
53
- briefPath = join(paths.outputs, "brief.md");
54
- await atomicWriteFile(briefPath, lines.join("\n"));
55
- }
56
- const verdictPath = join(paths.manifests, `${runId}.verdict.json`);
57
- const verdict = {
58
- schemaVersion: "psyclaw/verdict/v1",
59
- runId,
60
- verdict: blocked.length === 0 ? "pass" : "blocked",
61
- manifestPath,
62
- ...(briefPath ? { briefPath } : {}),
63
- gateCount: gates.length,
64
- blockedGateCount: blocked.length,
65
- generatedAt: new Date().toISOString(),
66
- };
67
- await atomicWriteFile(verdictPath, `${JSON.stringify(verdict, null, 2)}\n`);
68
- const handoff = await writeHandoff(root, {
69
- projectId: project.id,
70
- runId,
71
- goal: project.goal,
72
- completed: ["evidence ledger loaded", "evidence sufficiency gates evaluated"],
73
- verified: blocked.length === 0 ? ["brief.md", "manifest", "verdict"] : ["manifest", "verdict"],
74
- blocked: blocked.map((gate) => gate.reason),
75
- nextSteps: blocked.length === 0 ? ["review before external use"] : ["retrieve missing evidence, narrow unsupported statements, and rerun the checks"],
76
- verificationCommands: ["pnpm typecheck", "pnpm test"],
77
- generatedAt: new Date().toISOString(),
78
- });
79
- return { runId, verdict: blocked.length === 0 ? "pass" : "blocked", gates, ...(briefPath ? { briefPath } : {}), manifestPath, verdictPath, handoff };
80
- }
81
- //# sourceMappingURL=brief.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"brief.js","sourceRoot":"","sources":["../../../src/research/brief.ts"],"names":[],"mappings":"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"}
@@ -1,17 +0,0 @@
1
- ---
2
- name: research-brief
3
- description: Produce a concise, evidence-grounded research brief from an approved intake card and audited local evidence ledger.
4
- license: MIT
5
- ---
6
-
7
- # Research Brief
8
-
9
- Follow intake -> capture -> ledger -> audit -> write -> handoff. Write only from accepted evidence and label gaps, contradictions, exploratory claims, and human decisions. Include a provenance manifest, verification verdict, and executable handoff; do not invent citations, data, methods, or numerical results.
10
-
11
- For manuscript outputs, use continuous academic paragraphs rather than bullet-heavy notes. Apply a neutral submission format: Times New Roman for Latin text, SimSun/宋体 fallback for Chinese, black headings and body text, and no decorative color. Before finalization, ensure each factual or literature-dependent paragraph has a verified citation; if sources are insufficient, retrieve more or mark the section uncertain instead of fabricating references.
12
-
13
- Keep internal workflow language out of reader-facing prose. Translate Claim/Evidence checks into ordinary scholarly reasoning and avoid bureaucratic terms such as audit, blocked outcome, dependency, receipt, or gate. In Chinese psychology writing, prefer context-specific terms such as research statement, supporting literature, quality check, outcome variable or indicator, required software, and unavailable analysis. Remove stacked modifiers and repeated methodological disclaimers; state each necessary limitation once in the most relevant section.
14
-
15
- Follow the target venue's abstract instructions exactly. Without a supplied venue format, write one concise paragraph covering purpose, method, principal results, and conclusion; do not add explicit four-part labels by default. Keep column-level data diagnostics, hashes, implementation details, and exhaustive secondary results out of the abstract. Report data quality in aggregate in the manuscript and put complete variable-level diagnostics in supplementary material.
16
-
17
- Reference use is part of the manuscript, not a separate inventory. Apply one citation style consistently, make every in-text citation match exactly one reference entry and vice versa, preserve the publication type, and verify author order, year, title, journal or proceedings, volume, issue, pages or article number, DOI, punctuation, ordering, and hanging indent from source metadata. Never fill missing fields from memory.