flonat-research 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) hide show
  1. package/.claude/agents/domain-reviewer.md +336 -0
  2. package/.claude/agents/fixer.md +226 -0
  3. package/.claude/agents/paper-critic.md +370 -0
  4. package/.claude/agents/peer-reviewer.md +289 -0
  5. package/.claude/agents/proposal-reviewer.md +215 -0
  6. package/.claude/agents/referee2-reviewer.md +367 -0
  7. package/.claude/agents/references/journal-referee-profiles.md +354 -0
  8. package/.claude/agents/references/paper-critic/council-personas.md +77 -0
  9. package/.claude/agents/references/paper-critic/council-prompts.md +198 -0
  10. package/.claude/agents/references/peer-reviewer/report-template.md +199 -0
  11. package/.claude/agents/references/peer-reviewer/sa-prompts.md +260 -0
  12. package/.claude/agents/references/peer-reviewer/security-scan.md +188 -0
  13. package/.claude/agents/references/proposal-reviewer/report-template.md +144 -0
  14. package/.claude/agents/references/proposal-reviewer/sa-prompts.md +149 -0
  15. package/.claude/agents/references/referee-config.md +114 -0
  16. package/.claude/agents/references/referee2-reviewer/audit-checklists.md +287 -0
  17. package/.claude/agents/references/referee2-reviewer/report-template.md +334 -0
  18. package/.claude/rules/design-before-results.md +52 -0
  19. package/.claude/rules/ignore-agents-md.md +17 -0
  20. package/.claude/rules/ignore-gemini-md.md +17 -0
  21. package/.claude/rules/lean-claude-md.md +45 -0
  22. package/.claude/rules/learn-tags.md +99 -0
  23. package/.claude/rules/overleaf-separation.md +67 -0
  24. package/.claude/rules/plan-first.md +175 -0
  25. package/.claude/rules/read-docs-first.md +50 -0
  26. package/.claude/rules/scope-discipline.md +28 -0
  27. package/.claude/settings.json +125 -0
  28. package/.context/current-focus.md +33 -0
  29. package/.context/preferences/priorities.md +36 -0
  30. package/.context/preferences/task-naming.md +28 -0
  31. package/.context/profile.md +29 -0
  32. package/.context/projects/_index.md +41 -0
  33. package/.context/projects/papers/nudge-exp.md +22 -0
  34. package/.context/projects/papers/uncertainty.md +31 -0
  35. package/.context/resources/claude-scientific-writer-review.md +48 -0
  36. package/.context/resources/cunningham-multi-analyst-agents.md +104 -0
  37. package/.context/resources/cunningham-multilang-code-audit.md +62 -0
  38. package/.context/resources/google-ai-co-scientist-review.md +72 -0
  39. package/.context/resources/karpathy-llm-council-review.md +58 -0
  40. package/.context/resources/multi-coder-reliability-protocol.md +175 -0
  41. package/.context/resources/pedro-santanna-takeaways.md +96 -0
  42. package/.context/resources/venue-rankings/abs_ajg_2024.csv +1823 -0
  43. package/.context/resources/venue-rankings/abs_ajg_2024_econ.csv +356 -0
  44. package/.context/resources/venue-rankings/cabs_4_4star_theory.csv +40 -0
  45. package/.context/resources/venue-rankings/core_2026.csv +801 -0
  46. package/.context/resources/venue-rankings.md +147 -0
  47. package/.context/workflows/README.md +69 -0
  48. package/.context/workflows/daily-review.md +91 -0
  49. package/.context/workflows/meeting-actions.md +108 -0
  50. package/.context/workflows/replication-protocol.md +155 -0
  51. package/.context/workflows/weekly-review.md +113 -0
  52. package/.mcp-server-biblio/formatters.py +158 -0
  53. package/.mcp-server-biblio/pyproject.toml +11 -0
  54. package/.mcp-server-biblio/server.py +678 -0
  55. package/.mcp-server-biblio/sources/__init__.py +14 -0
  56. package/.mcp-server-biblio/sources/base.py +73 -0
  57. package/.mcp-server-biblio/sources/formatters.py +83 -0
  58. package/.mcp-server-biblio/sources/models.py +22 -0
  59. package/.mcp-server-biblio/sources/multi_source.py +243 -0
  60. package/.mcp-server-biblio/sources/openalex_source.py +183 -0
  61. package/.mcp-server-biblio/sources/scopus_source.py +309 -0
  62. package/.mcp-server-biblio/sources/wos_source.py +508 -0
  63. package/.mcp-server-biblio/uv.lock +896 -0
  64. package/.scripts/README.md +161 -0
  65. package/.scripts/ai_pattern_density.py +446 -0
  66. package/.scripts/conf +445 -0
  67. package/.scripts/config.py +122 -0
  68. package/.scripts/count_inventory.py +275 -0
  69. package/.scripts/daily_digest.py +288 -0
  70. package/.scripts/done +177 -0
  71. package/.scripts/extract_meeting_actions.py +223 -0
  72. package/.scripts/focus +176 -0
  73. package/.scripts/generate-codex-agents-md.py +217 -0
  74. package/.scripts/inbox +194 -0
  75. package/.scripts/notion_helpers.py +325 -0
  76. package/.scripts/openalex/query_helpers.py +306 -0
  77. package/.scripts/papers +227 -0
  78. package/.scripts/query +223 -0
  79. package/.scripts/session-history.py +201 -0
  80. package/.scripts/skill-health.py +516 -0
  81. package/.scripts/skill-log-miner.py +273 -0
  82. package/.scripts/sync-to-codex.sh +252 -0
  83. package/.scripts/task +213 -0
  84. package/.scripts/tasks +190 -0
  85. package/.scripts/week +206 -0
  86. package/CLAUDE.md +197 -0
  87. package/LICENSE +21 -0
  88. package/MEMORY.md +38 -0
  89. package/README.md +269 -0
  90. package/docs/agents.md +44 -0
  91. package/docs/bibliography-setup.md +55 -0
  92. package/docs/council-mode.md +36 -0
  93. package/docs/getting-started.md +245 -0
  94. package/docs/hooks.md +38 -0
  95. package/docs/mcp-servers.md +82 -0
  96. package/docs/notion-setup.md +109 -0
  97. package/docs/rules.md +33 -0
  98. package/docs/scripts.md +303 -0
  99. package/docs/setup-overview/setup-overview.pdf +0 -0
  100. package/docs/skills.md +70 -0
  101. package/docs/system.md +159 -0
  102. package/hooks/block-destructive-git.sh +66 -0
  103. package/hooks/context-monitor.py +114 -0
  104. package/hooks/postcompact-restore.py +157 -0
  105. package/hooks/precompact-autosave.py +181 -0
  106. package/hooks/promise-checker.sh +124 -0
  107. package/hooks/protect-source-files.sh +81 -0
  108. package/hooks/resume-context-loader.sh +53 -0
  109. package/hooks/startup-context-loader.sh +102 -0
  110. package/package.json +51 -0
  111. package/packages/cli-council/.github/workflows/claude-code-review.yml +44 -0
  112. package/packages/cli-council/.github/workflows/claude.yml +50 -0
  113. package/packages/cli-council/README.md +100 -0
  114. package/packages/cli-council/pyproject.toml +43 -0
  115. package/packages/cli-council/src/cli_council/__init__.py +19 -0
  116. package/packages/cli-council/src/cli_council/__main__.py +185 -0
  117. package/packages/cli-council/src/cli_council/backends/__init__.py +8 -0
  118. package/packages/cli-council/src/cli_council/backends/base.py +81 -0
  119. package/packages/cli-council/src/cli_council/backends/claude.py +25 -0
  120. package/packages/cli-council/src/cli_council/backends/codex.py +27 -0
  121. package/packages/cli-council/src/cli_council/backends/gemini.py +26 -0
  122. package/packages/cli-council/src/cli_council/checkpoint.py +212 -0
  123. package/packages/cli-council/src/cli_council/config.py +51 -0
  124. package/packages/cli-council/src/cli_council/council.py +391 -0
  125. package/packages/cli-council/src/cli_council/models.py +46 -0
  126. package/packages/llm-council/.github/workflows/claude-code-review.yml +44 -0
  127. package/packages/llm-council/.github/workflows/claude.yml +50 -0
  128. package/packages/llm-council/README.md +453 -0
  129. package/packages/llm-council/pyproject.toml +42 -0
  130. package/packages/llm-council/src/llm_council/__init__.py +23 -0
  131. package/packages/llm-council/src/llm_council/__main__.py +259 -0
  132. package/packages/llm-council/src/llm_council/checkpoint.py +193 -0
  133. package/packages/llm-council/src/llm_council/client.py +253 -0
  134. package/packages/llm-council/src/llm_council/config.py +232 -0
  135. package/packages/llm-council/src/llm_council/council.py +482 -0
  136. package/packages/llm-council/src/llm_council/models.py +46 -0
  137. package/packages/mcp-bibliography/MEMORY.md +31 -0
  138. package/packages/mcp-bibliography/_app.py +226 -0
  139. package/packages/mcp-bibliography/formatters.py +158 -0
  140. package/packages/mcp-bibliography/log/2026-03-13-2100.md +35 -0
  141. package/packages/mcp-bibliography/pyproject.toml +15 -0
  142. package/packages/mcp-bibliography/run.sh +20 -0
  143. package/packages/mcp-bibliography/scholarly_formatters.py +83 -0
  144. package/packages/mcp-bibliography/server.py +1857 -0
  145. package/packages/mcp-bibliography/tools/__init__.py +28 -0
  146. package/packages/mcp-bibliography/tools/_registry.py +19 -0
  147. package/packages/mcp-bibliography/tools/altmetric.py +107 -0
  148. package/packages/mcp-bibliography/tools/core.py +92 -0
  149. package/packages/mcp-bibliography/tools/dblp.py +52 -0
  150. package/packages/mcp-bibliography/tools/openalex.py +296 -0
  151. package/packages/mcp-bibliography/tools/opencitations.py +102 -0
  152. package/packages/mcp-bibliography/tools/openreview.py +179 -0
  153. package/packages/mcp-bibliography/tools/orcid.py +131 -0
  154. package/packages/mcp-bibliography/tools/scholarly.py +575 -0
  155. package/packages/mcp-bibliography/tools/unpaywall.py +63 -0
  156. package/packages/mcp-bibliography/tools/zenodo.py +123 -0
  157. package/packages/mcp-bibliography/uv.lock +711 -0
  158. package/scripts/setup.sh +143 -0
  159. package/skills/beamer-deck/SKILL.md +199 -0
  160. package/skills/beamer-deck/references/quality-rubric.md +54 -0
  161. package/skills/beamer-deck/references/review-prompts.md +106 -0
  162. package/skills/bib-validate/SKILL.md +261 -0
  163. package/skills/bib-validate/references/council-mode.md +34 -0
  164. package/skills/bib-validate/references/deep-verify.md +79 -0
  165. package/skills/bib-validate/references/fix-mode.md +36 -0
  166. package/skills/bib-validate/references/openalex-verification.md +45 -0
  167. package/skills/bib-validate/references/preprint-check.md +31 -0
  168. package/skills/bib-validate/references/ref-manager-crossref.md +41 -0
  169. package/skills/bib-validate/references/report-template.md +82 -0
  170. package/skills/code-archaeology/SKILL.md +141 -0
  171. package/skills/code-review/SKILL.md +265 -0
  172. package/skills/code-review/references/quality-rubric.md +67 -0
  173. package/skills/consolidate-memory/SKILL.md +208 -0
  174. package/skills/context-status/SKILL.md +126 -0
  175. package/skills/creation-guard/SKILL.md +230 -0
  176. package/skills/devils-advocate/SKILL.md +130 -0
  177. package/skills/devils-advocate/references/competing-hypotheses.md +83 -0
  178. package/skills/init-project/SKILL.md +115 -0
  179. package/skills/init-project-course/references/memory-and-settings.md +92 -0
  180. package/skills/init-project-course/references/organise-templates.md +94 -0
  181. package/skills/init-project-course/skill.md +147 -0
  182. package/skills/init-project-light/skill.md +139 -0
  183. package/skills/init-project-research/SKILL.md +368 -0
  184. package/skills/init-project-research/references/atlas-pipeline-sync.md +70 -0
  185. package/skills/init-project-research/references/atlas-schema.md +81 -0
  186. package/skills/init-project-research/references/confirmation-report.md +39 -0
  187. package/skills/init-project-research/references/domain-profile-template.md +104 -0
  188. package/skills/init-project-research/references/interview-round3.md +34 -0
  189. package/skills/init-project-research/references/literature-discovery.md +43 -0
  190. package/skills/init-project-research/references/scaffold-details.md +197 -0
  191. package/skills/init-project-research/templates/field-calibration.md +60 -0
  192. package/skills/init-project-research/templates/pipeline-manifest.md +63 -0
  193. package/skills/init-project-research/templates/run-all.sh +116 -0
  194. package/skills/init-project-research/templates/seed-files.md +337 -0
  195. package/skills/insights-deck/SKILL.md +151 -0
  196. package/skills/interview-me/SKILL.md +157 -0
  197. package/skills/latex/SKILL.md +141 -0
  198. package/skills/latex/references/latex-configs.md +183 -0
  199. package/skills/latex-autofix/SKILL.md +230 -0
  200. package/skills/latex-autofix/references/known-errors.md +183 -0
  201. package/skills/latex-autofix/references/quality-rubric.md +50 -0
  202. package/skills/latex-health-check/SKILL.md +161 -0
  203. package/skills/learn/SKILL.md +220 -0
  204. package/skills/learn/scripts/validate_skill.py +265 -0
  205. package/skills/lessons-learned/SKILL.md +201 -0
  206. package/skills/literature/SKILL.md +335 -0
  207. package/skills/literature/references/agent-templates.md +393 -0
  208. package/skills/literature/references/bibliometric-apis.md +44 -0
  209. package/skills/literature/references/cli-council-search.md +79 -0
  210. package/skills/literature/references/openalex-api-guide.md +371 -0
  211. package/skills/literature/references/openalex-common-queries.md +381 -0
  212. package/skills/literature/references/openalex-workflows.md +248 -0
  213. package/skills/literature/references/reference-manager-sync.md +36 -0
  214. package/skills/literature/references/scopus-api-guide.md +208 -0
  215. package/skills/literature/references/wos-api-guide.md +308 -0
  216. package/skills/multi-perspective/SKILL.md +311 -0
  217. package/skills/multi-perspective/references/computational-many-analysts.md +77 -0
  218. package/skills/pipeline-manifest/SKILL.md +226 -0
  219. package/skills/pre-submission-report/SKILL.md +153 -0
  220. package/skills/process-reviews/SKILL.md +244 -0
  221. package/skills/process-reviews/references/rr-routing.md +101 -0
  222. package/skills/project-deck/SKILL.md +87 -0
  223. package/skills/project-safety/SKILL.md +135 -0
  224. package/skills/proofread/SKILL.md +254 -0
  225. package/skills/proofread/references/quality-rubric.md +104 -0
  226. package/skills/python-env/SKILL.md +57 -0
  227. package/skills/quarto-deck/SKILL.md +226 -0
  228. package/skills/quarto-deck/references/markdown-format.md +143 -0
  229. package/skills/quarto-deck/references/quality-rubric.md +54 -0
  230. package/skills/save-context/SKILL.md +174 -0
  231. package/skills/session-log/SKILL.md +98 -0
  232. package/skills/shared/concept-validation-gate.md +161 -0
  233. package/skills/shared/council-protocol.md +265 -0
  234. package/skills/shared/distribution-diagnostics.md +164 -0
  235. package/skills/shared/engagement-stratified-sampling.md +218 -0
  236. package/skills/shared/escalation-protocol.md +74 -0
  237. package/skills/shared/external-audit-protocol.md +205 -0
  238. package/skills/shared/intercoder-reliability.md +256 -0
  239. package/skills/shared/mcp-degradation.md +81 -0
  240. package/skills/shared/method-probing-questions.md +163 -0
  241. package/skills/shared/multi-language-conventions.md +143 -0
  242. package/skills/shared/paid-api-safety.md +174 -0
  243. package/skills/shared/palettes.md +90 -0
  244. package/skills/shared/progressive-disclosure.md +92 -0
  245. package/skills/shared/project-documentation-content.md +443 -0
  246. package/skills/shared/project-documentation-format.md +281 -0
  247. package/skills/shared/project-documentation.md +100 -0
  248. package/skills/shared/publication-output.md +138 -0
  249. package/skills/shared/quality-scoring.md +70 -0
  250. package/skills/shared/reference-resolution.md +77 -0
  251. package/skills/shared/research-quality-rubric.md +165 -0
  252. package/skills/shared/rhetoric-principles.md +54 -0
  253. package/skills/shared/skill-design-patterns.md +272 -0
  254. package/skills/shared/skill-index.md +240 -0
  255. package/skills/shared/system-documentation.md +334 -0
  256. package/skills/shared/tikz-rules.md +402 -0
  257. package/skills/shared/validation-tiers.md +121 -0
  258. package/skills/shared/venue-guides/README.md +46 -0
  259. package/skills/shared/venue-guides/cell_press_style.md +483 -0
  260. package/skills/shared/venue-guides/conferences_formatting.md +564 -0
  261. package/skills/shared/venue-guides/cs_conference_style.md +463 -0
  262. package/skills/shared/venue-guides/examples/cell_summary_example.md +247 -0
  263. package/skills/shared/venue-guides/examples/medical_structured_abstract.md +313 -0
  264. package/skills/shared/venue-guides/examples/nature_abstract_examples.md +213 -0
  265. package/skills/shared/venue-guides/examples/neurips_introduction_example.md +245 -0
  266. package/skills/shared/venue-guides/journals_formatting.md +486 -0
  267. package/skills/shared/venue-guides/medical_journal_styles.md +535 -0
  268. package/skills/shared/venue-guides/ml_conference_style.md +556 -0
  269. package/skills/shared/venue-guides/nature_science_style.md +405 -0
  270. package/skills/shared/venue-guides/reviewer_expectations.md +417 -0
  271. package/skills/shared/venue-guides/venue_writing_styles.md +321 -0
  272. package/skills/split-pdf/SKILL.md +172 -0
  273. package/skills/split-pdf/methodology.md +48 -0
  274. package/skills/sync-notion/SKILL.md +93 -0
  275. package/skills/system-audit/SKILL.md +157 -0
  276. package/skills/system-audit/references/sub-agent-prompts.md +294 -0
  277. package/skills/task-management/SKILL.md +131 -0
  278. package/skills/update-focus/SKILL.md +204 -0
  279. package/skills/update-project-doc/SKILL.md +194 -0
  280. package/skills/validate-bib/SKILL.md +242 -0
  281. package/skills/validate-bib/references/council-mode.md +34 -0
  282. package/skills/validate-bib/references/deep-verify.md +71 -0
  283. package/skills/validate-bib/references/openalex-verification.md +45 -0
  284. package/skills/validate-bib/references/preprint-check.md +31 -0
  285. package/skills/validate-bib/references/report-template.md +62 -0
package/.scripts/task ADDED
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Quick task entry for Notion Tasks Tracker.
4
+
5
+ Creates tasks with "Inbox" status by default (GTD-style capture).
6
+ Requires "Inbox" status option to exist in Notion Tasks tracker.
7
+
8
+ Usage:
9
+ task "Task description"
10
+ task "Task description" --project "Journal Revision" --priority high
11
+ task "Task description" -p "[Project]" -d tomorrow
12
+ task "Read paper" --area Research
13
+ """
14
+
15
+ import argparse
16
+ import json
17
+ import os
18
+ import sys
19
+ import urllib.request
20
+ import urllib.error
21
+ from datetime import datetime, timedelta
22
+
23
+
24
+ # Configuration
25
+ NOTION_TOKEN = os.environ.get("NOTION_TOKEN")
26
+ DATABASE_ID = "YOUR-TASKS-DATABASE-ID-HERE"
27
+
28
+ PROJECTS = [
29
+ "Journal Revision",
30
+ "[Project] Theory",
31
+ "Objective-Architecture",
32
+ "[Project]",
33
+ "AI Mental Health",
34
+ "API Transparency",
35
+ "[Project] Research",
36
+ "Teaching",
37
+ "Personal Admin",
38
+ ]
39
+
40
+ PRIORITIES = ["High", "Medium", "Low"]
41
+
42
+ AREAS = ["Research", "Teaching", "Career", "Personal", "Health", "Learning"]
43
+
44
+ SOURCES = [
45
+ "Meeting",
46
+ "Email",
47
+ "Supervisor request",
48
+ "Self-initiated",
49
+ "Deadline/calendar",
50
+ "Idea capture",
51
+ ]
52
+
53
+
54
+ def parse_date(date_str: str) -> str:
55
+ """Parse natural language dates."""
56
+ today = datetime.now()
57
+ date_lower = date_str.lower()
58
+
59
+ if date_lower == "today":
60
+ return today.strftime("%Y-%m-%d")
61
+ elif date_lower == "tomorrow":
62
+ return (today + timedelta(days=1)).strftime("%Y-%m-%d")
63
+ elif date_lower in ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]:
64
+ days = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
65
+ target = days.index(date_lower)
66
+ current = today.weekday()
67
+ diff = target - current
68
+ if diff <= 0:
69
+ diff += 7
70
+ return (today + timedelta(days=diff)).strftime("%Y-%m-%d")
71
+ else:
72
+ # Try to parse as YYYY-MM-DD or DD/MM/YYYY
73
+ for fmt in ["%Y-%m-%d", "%d/%m/%Y", "%d-%m-%Y"]:
74
+ try:
75
+ return datetime.strptime(date_str, fmt).strftime("%Y-%m-%d")
76
+ except ValueError:
77
+ continue
78
+ return date_str
79
+
80
+
81
+ def create_task(
82
+ name: str,
83
+ project: str = None,
84
+ priority: str = "Medium",
85
+ due_date: str = None,
86
+ source: str = "Self-initiated",
87
+ area: str = None,
88
+ description: str = None,
89
+ ):
90
+ """Create a task in Notion."""
91
+
92
+ if not NOTION_TOKEN:
93
+ print("āŒ NOTION_TOKEN not set. Run:")
94
+ print(' export NOTION_TOKEN="your-token-here"')
95
+ print("\nGet a token at: https://www.notion.so/my-integrations")
96
+ sys.exit(1)
97
+
98
+ # Build properties
99
+ properties = {
100
+ "Task name": {
101
+ "title": [{"text": {"content": name}}]
102
+ },
103
+ "Status": {
104
+ "status": {"name": "Inbox"}
105
+ },
106
+ "Priority": {
107
+ "select": {"name": priority}
108
+ },
109
+ "Source": {
110
+ "select": {"name": source}
111
+ },
112
+ }
113
+
114
+ if project:
115
+ properties["Project"] = {"select": {"name": project}}
116
+
117
+ if area:
118
+ properties["Area"] = {"select": {"name": area}}
119
+
120
+ if due_date:
121
+ properties["Due date"] = {"date": {"start": parse_date(due_date)}}
122
+
123
+ if description:
124
+ properties["Description"] = {
125
+ "rich_text": [{"text": {"content": description}}]
126
+ }
127
+
128
+ data = {
129
+ "parent": {"database_id": DATABASE_ID},
130
+ "properties": properties,
131
+ }
132
+
133
+ # Make request using urllib (built-in)
134
+ req = urllib.request.Request(
135
+ "https://api.notion.com/v1/pages",
136
+ data=json.dumps(data).encode("utf-8"),
137
+ headers={
138
+ "Authorization": f"Bearer {NOTION_TOKEN}",
139
+ "Content-Type": "application/json",
140
+ "Notion-Version": "2022-06-28",
141
+ },
142
+ method="POST",
143
+ )
144
+
145
+ try:
146
+ with urllib.request.urlopen(req) as response:
147
+ result = json.loads(response.read().decode("utf-8"))
148
+ url = result.get("url", "")
149
+ print(f"āœ… Created: {name}")
150
+ if project:
151
+ print(f" Project: {project}")
152
+ if due_date:
153
+ print(f" Due: {parse_date(due_date)}")
154
+ print(f" {url}")
155
+ except urllib.error.HTTPError as e:
156
+ error_body = json.loads(e.read().decode("utf-8"))
157
+ print(f"āŒ Error: {e.code}")
158
+ print(error_body.get("message", str(error_body)))
159
+
160
+
161
+ def list_projects():
162
+ """List available projects."""
163
+ print("Available projects:")
164
+ for p in PROJECTS:
165
+ print(f" - {p}")
166
+
167
+
168
+ def main():
169
+ parser = argparse.ArgumentParser(
170
+ description="Quick task entry for Notion",
171
+ formatter_class=argparse.RawDescriptionHelpFormatter,
172
+ epilog="""
173
+ Examples:
174
+ task "Review [Journal] feedback"
175
+ task "Email [Supervisor] about results" -p "Journal Revision" --priority high
176
+ task "Read Smith 2024 paper" -p "[Project]" -d friday
177
+ task "Submit expenses" -p "Personal Admin" -d tomorrow
178
+ """,
179
+ )
180
+
181
+ parser.add_argument("name", nargs="?", help="Task description")
182
+ parser.add_argument("-p", "--project", help="Project name")
183
+ parser.add_argument("--priority", choices=["high", "medium", "low"], default="medium")
184
+ parser.add_argument("-d", "--due", help="Due date (today, tomorrow, friday, 2024-01-15)")
185
+ parser.add_argument("-s", "--source", default="Self-initiated")
186
+ parser.add_argument("-a", "--area", choices=["research", "teaching", "career", "personal", "health", "learning"],
187
+ help="Area of responsibility")
188
+ parser.add_argument("--desc", help="Additional description")
189
+ parser.add_argument("--list-projects", action="store_true", help="List available projects")
190
+
191
+ args = parser.parse_args()
192
+
193
+ if args.list_projects:
194
+ list_projects()
195
+ return
196
+
197
+ if not args.name:
198
+ parser.print_help()
199
+ return
200
+
201
+ create_task(
202
+ name=args.name,
203
+ project=args.project,
204
+ priority=args.priority.capitalize(),
205
+ due_date=args.due,
206
+ source=args.source,
207
+ area=args.area.capitalize() if args.area else None,
208
+ description=args.desc,
209
+ )
210
+
211
+
212
+ if __name__ == "__main__":
213
+ main()
package/.scripts/tasks ADDED
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Query and list tasks from Notion Tasks Tracker.
4
+
5
+ Usage:
6
+ tasks # Show all active tasks
7
+ tasks --overdue # Show overdue tasks
8
+ tasks --today # Show tasks due today
9
+ tasks -p "Journal Revision" # Filter by project
10
+ tasks --priority high # Filter by priority
11
+ """
12
+
13
+ import argparse
14
+ import json
15
+ import os
16
+ import sys
17
+ import urllib.request
18
+ import urllib.error
19
+ from datetime import datetime
20
+
21
+
22
+ NOTION_TOKEN = os.environ.get("NOTION_TOKEN")
23
+ DATABASE_ID = "YOUR-TASKS-DATABASE-ID-HERE"
24
+
25
+
26
+ def query_tasks(filter_obj=None, sorts=None):
27
+ """Query tasks from Notion."""
28
+ if not NOTION_TOKEN:
29
+ print("āŒ NOTION_TOKEN not set")
30
+ sys.exit(1)
31
+
32
+ data = {}
33
+ if filter_obj:
34
+ data["filter"] = filter_obj
35
+ if sorts:
36
+ data["sorts"] = sorts
37
+
38
+ req = urllib.request.Request(
39
+ f"https://api.notion.com/v1/databases/{DATABASE_ID}/query",
40
+ data=json.dumps(data).encode("utf-8") if data else b"{}",
41
+ headers={
42
+ "Authorization": f"Bearer {NOTION_TOKEN}",
43
+ "Content-Type": "application/json",
44
+ "Notion-Version": "2022-06-28",
45
+ },
46
+ method="POST",
47
+ )
48
+
49
+ try:
50
+ with urllib.request.urlopen(req) as response:
51
+ return json.loads(response.read().decode("utf-8"))
52
+ except urllib.error.HTTPError as e:
53
+ error_body = json.loads(e.read().decode("utf-8"))
54
+ print(f"āŒ Error: {e.code}")
55
+ print(error_body.get("message", str(error_body)))
56
+ sys.exit(1)
57
+
58
+
59
+ def get_property(page, prop_name, prop_type):
60
+ """Extract property value from a Notion page."""
61
+ prop = page.get("properties", {}).get(prop_name, {})
62
+
63
+ if prop_type == "title":
64
+ title_list = prop.get("title", [])
65
+ return title_list[0].get("plain_text", "") if title_list else ""
66
+ elif prop_type == "select":
67
+ select = prop.get("select")
68
+ return select.get("name", "") if select else ""
69
+ elif prop_type == "status":
70
+ status = prop.get("status")
71
+ return status.get("name", "") if status else ""
72
+ elif prop_type == "date":
73
+ date = prop.get("date")
74
+ return date.get("start", "") if date else ""
75
+ elif prop_type == "rich_text":
76
+ text_list = prop.get("rich_text", [])
77
+ return text_list[0].get("plain_text", "") if text_list else ""
78
+ return ""
79
+
80
+
81
+ def format_task(page):
82
+ """Format a task for display."""
83
+ name = get_property(page, "Task name", "title")
84
+ status = get_property(page, "Status", "status")
85
+ priority = get_property(page, "Priority", "select")
86
+ project = get_property(page, "Project", "select")
87
+ due = get_property(page, "Due date", "date")
88
+
89
+ priority_emoji = {"High": "šŸ”“", "Medium": "🟔", "Low": "🟢"}.get(priority, "⚪")
90
+ status_emoji = {"Done": "āœ…", "In progress": "šŸ”„", "Waiting": "ā³", "Not started": "⬜"}.get(status, "⬜")
91
+
92
+ line = f"{status_emoji} {priority_emoji} {name}"
93
+ if project:
94
+ line += f" [{project}]"
95
+ if due:
96
+ line += f" (due: {due})"
97
+
98
+ return line
99
+
100
+
101
+ def main():
102
+ parser = argparse.ArgumentParser(description="Query tasks from Notion")
103
+ parser.add_argument("--overdue", action="store_true", help="Show overdue tasks")
104
+ parser.add_argument("--today", action="store_true", help="Show tasks due today")
105
+ parser.add_argument("--week", action="store_true", help="Show tasks due this week")
106
+ parser.add_argument("-p", "--project", help="Filter by project")
107
+ parser.add_argument("--priority", choices=["high", "medium", "low"], help="Filter by priority")
108
+ parser.add_argument("--status", help="Filter by status")
109
+ parser.add_argument("--all", action="store_true", help="Include completed tasks")
110
+ parser.add_argument("--limit", type=int, default=20, help="Max results (default: 20)")
111
+
112
+ args = parser.parse_args()
113
+
114
+ # Build filter
115
+ filters = []
116
+ today = datetime.now().strftime("%Y-%m-%d")
117
+
118
+ # Exclude done unless --all
119
+ if not args.all:
120
+ filters.append({
121
+ "property": "Status",
122
+ "status": {"does_not_equal": "Done"}
123
+ })
124
+
125
+ if args.overdue:
126
+ filters.append({
127
+ "property": "Due date",
128
+ "date": {"before": today}
129
+ })
130
+
131
+ if args.today:
132
+ filters.append({
133
+ "property": "Due date",
134
+ "date": {"equals": today}
135
+ })
136
+
137
+ if args.project:
138
+ filters.append({
139
+ "property": "Project",
140
+ "select": {"equals": args.project}
141
+ })
142
+
143
+ if args.priority:
144
+ filters.append({
145
+ "property": "Priority",
146
+ "select": {"equals": args.priority.capitalize()}
147
+ })
148
+
149
+ if args.status:
150
+ filters.append({
151
+ "property": "Status",
152
+ "status": {"equals": args.status}
153
+ })
154
+
155
+ filter_obj = None
156
+ if len(filters) == 1:
157
+ filter_obj = filters[0]
158
+ elif len(filters) > 1:
159
+ filter_obj = {"and": filters}
160
+
161
+ # Sort by due date, then priority
162
+ sorts = [
163
+ {"property": "Due date", "direction": "ascending"},
164
+ {"property": "Priority", "direction": "ascending"},
165
+ ]
166
+
167
+ result = query_tasks(filter_obj, sorts)
168
+ pages = result.get("results", [])[:args.limit]
169
+
170
+ if not pages:
171
+ print("No tasks found.")
172
+ return
173
+
174
+ # Print header
175
+ if args.overdue:
176
+ print(f"āš ļø Overdue Tasks ({len(pages)})")
177
+ elif args.today:
178
+ print(f"šŸ“… Due Today ({len(pages)})")
179
+ elif args.project:
180
+ print(f"šŸ“ {args.project} ({len(pages)})")
181
+ else:
182
+ print(f"šŸ“‹ Tasks ({len(pages)})")
183
+ print("-" * 40)
184
+
185
+ for page in pages:
186
+ print(format_task(page))
187
+
188
+
189
+ if __name__ == "__main__":
190
+ main()
package/.scripts/week ADDED
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Generate weekly summary from Notion tasks.
4
+
5
+ Usage:
6
+ week # Show this week's summary
7
+ week --last # Show last week's summary
8
+ """
9
+
10
+ import argparse
11
+ import json
12
+ import os
13
+ import sys
14
+ import urllib.request
15
+ import urllib.error
16
+ from datetime import datetime, timedelta
17
+
18
+
19
+ NOTION_TOKEN = os.environ.get("NOTION_TOKEN")
20
+ DATABASE_ID = "YOUR-TASKS-DATABASE-ID-HERE"
21
+
22
+
23
+ def get_week_range(last_week=False):
24
+ """Get start and end of current or last week."""
25
+ today = datetime.now()
26
+
27
+ # Start of current week (Monday)
28
+ start_of_week = today - timedelta(days=today.weekday())
29
+
30
+ if last_week:
31
+ start_of_week = start_of_week - timedelta(days=7)
32
+
33
+ end_of_week = start_of_week + timedelta(days=6)
34
+
35
+ return start_of_week.strftime("%Y-%m-%d"), end_of_week.strftime("%Y-%m-%d")
36
+
37
+
38
+ def query_tasks(filter_obj):
39
+ """Query tasks from Notion."""
40
+ if not NOTION_TOKEN:
41
+ print("āŒ NOTION_TOKEN not set")
42
+ sys.exit(1)
43
+
44
+ data = {"filter": filter_obj}
45
+
46
+ req = urllib.request.Request(
47
+ f"https://api.notion.com/v1/databases/{DATABASE_ID}/query",
48
+ data=json.dumps(data).encode("utf-8"),
49
+ headers={
50
+ "Authorization": f"Bearer {NOTION_TOKEN}",
51
+ "Content-Type": "application/json",
52
+ "Notion-Version": "2022-06-28",
53
+ },
54
+ method="POST",
55
+ )
56
+
57
+ try:
58
+ with urllib.request.urlopen(req) as response:
59
+ return json.loads(response.read().decode("utf-8"))
60
+ except urllib.error.HTTPError as e:
61
+ error_body = json.loads(e.read().decode("utf-8"))
62
+ print(f"āŒ Error: {e.code}")
63
+ print(error_body.get("message", str(error_body)))
64
+ sys.exit(1)
65
+
66
+
67
+ def get_property(page, prop_name, prop_type):
68
+ """Extract property value from a Notion page."""
69
+ prop = page.get("properties", {}).get(prop_name, {})
70
+
71
+ if prop_type == "title":
72
+ title_list = prop.get("title", [])
73
+ return title_list[0].get("plain_text", "") if title_list else ""
74
+ elif prop_type == "select":
75
+ select = prop.get("select")
76
+ return select.get("name", "") if select else ""
77
+ elif prop_type == "status":
78
+ status = prop.get("status")
79
+ return status.get("name", "") if status else ""
80
+ elif prop_type == "date":
81
+ date = prop.get("date")
82
+ return date.get("start", "") if date else ""
83
+ return ""
84
+
85
+
86
+ def format_task(page):
87
+ """Format a task for display."""
88
+ title = get_property(page, "Task name", "title")
89
+ project = get_property(page, "Project", "select")
90
+
91
+ line = f" • {title}"
92
+ if project:
93
+ line += f" [{project}]"
94
+
95
+ return line
96
+
97
+
98
+ def main():
99
+ parser = argparse.ArgumentParser(description="Weekly summary")
100
+ parser.add_argument("--last", action="store_true", help="Show last week instead")
101
+
102
+ args = parser.parse_args()
103
+
104
+ start_date, end_date = get_week_range(args.last)
105
+ today = datetime.now().strftime("%Y-%m-%d")
106
+
107
+ # Header
108
+ if args.last:
109
+ print(f"šŸ“… Last Week ({start_date} to {end_date})")
110
+ else:
111
+ print(f"šŸ“… This Week ({start_date} to {end_date})")
112
+ print("=" * 50)
113
+
114
+ # Completed tasks (status = Done, check last_edited_time in range)
115
+ # Note: We'll query Done tasks and filter by those edited this week
116
+ completed_result = query_tasks({
117
+ "property": "Status",
118
+ "status": {"equals": "Done"}
119
+ })
120
+ completed_pages = completed_result.get("results", [])
121
+
122
+ # Filter by last_edited_time (rough proxy for completion date)
123
+ completed_this_week = []
124
+ for page in completed_pages:
125
+ edited = page.get("last_edited_time", "")[:10]
126
+ if start_date <= edited <= end_date:
127
+ completed_this_week.append(page)
128
+
129
+ print(f"\nāœ… Completed ({len(completed_this_week)})")
130
+ print("-" * 30)
131
+ if completed_this_week:
132
+ for page in completed_this_week[:15]:
133
+ print(format_task(page))
134
+ if len(completed_this_week) > 15:
135
+ print(f" ... and {len(completed_this_week) - 15} more")
136
+ else:
137
+ print(" (none)")
138
+
139
+ # Due this week (not done)
140
+ due_result = query_tasks({
141
+ "and": [
142
+ {"property": "Status", "status": {"does_not_equal": "Done"}},
143
+ {"property": "Due date", "date": {"on_or_after": start_date}},
144
+ {"property": "Due date", "date": {"on_or_before": end_date}}
145
+ ]
146
+ })
147
+ due_pages = due_result.get("results", [])
148
+
149
+ print(f"\nšŸ“‹ Due This Week ({len(due_pages)})")
150
+ print("-" * 30)
151
+ if due_pages:
152
+ for page in due_pages:
153
+ due = get_property(page, "Due date", "date")
154
+ title = get_property(page, "Task name", "title")
155
+ project = get_property(page, "Project", "select")
156
+
157
+ overdue = "āš ļø " if due < today else ""
158
+ line = f" {overdue}• {title}"
159
+ if project:
160
+ line += f" [{project}]"
161
+ line += f" (due: {due})"
162
+ print(line)
163
+ else:
164
+ print(" (none)")
165
+
166
+ # Overdue
167
+ overdue_result = query_tasks({
168
+ "and": [
169
+ {"property": "Status", "status": {"does_not_equal": "Done"}},
170
+ {"property": "Due date", "date": {"before": today}}
171
+ ]
172
+ })
173
+ overdue_pages = overdue_result.get("results", [])
174
+
175
+ if overdue_pages:
176
+ print(f"\nāš ļø Overdue ({len(overdue_pages)})")
177
+ print("-" * 30)
178
+ for page in overdue_pages[:10]:
179
+ print(format_task(page))
180
+ if len(overdue_pages) > 10:
181
+ print(f" ... and {len(overdue_pages) - 10} more")
182
+
183
+ # In Progress
184
+ in_progress_result = query_tasks({
185
+ "property": "Status",
186
+ "status": {"equals": "In progress"}
187
+ })
188
+ in_progress_pages = in_progress_result.get("results", [])
189
+
190
+ if in_progress_pages:
191
+ print(f"\nšŸ”„ In Progress ({len(in_progress_pages)})")
192
+ print("-" * 30)
193
+ for page in in_progress_pages:
194
+ print(format_task(page))
195
+
196
+ # Summary stats
197
+ print("\n" + "=" * 50)
198
+ print("Summary:")
199
+ print(f" Completed: {len(completed_this_week)}")
200
+ print(f" Due this week: {len(due_pages)}")
201
+ print(f" Overdue: {len(overdue_pages)}")
202
+ print(f" In progress: {len(in_progress_pages)}")
203
+
204
+
205
+ if __name__ == "__main__":
206
+ main()