thoth-plugin 1.1.1 → 1.1.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.
- package/README.md +237 -31
- package/dist/cli.d.ts +3 -2
- package/dist/cli.js +248 -5
- package/dist/config/schema.d.ts +2 -0
- package/dist/defaults/skill/email-draft/skill.md +134 -0
- package/dist/defaults/skill/evening-close/SKILL.md +7 -0
- package/dist/defaults/skill/gardener/SKILL.md +36 -1
- package/dist/defaults/skill/leadership-coach/SKILL.md +7 -0
- package/dist/defaults/skill/mail-triage/SKILL.md +7 -0
- package/dist/defaults/skill/morning-boot/SKILL.md +8 -0
- package/dist/defaults/skill/post-meeting-drill/SKILL.md +6 -0
- package/dist/defaults/skill/skill-generator/SKILL.md +150 -28
- package/dist/defaults/skill/slack-pulse/SKILL.md +6 -0
- package/dist/defaults/skill/thought-router/SKILL.md +7 -0
- package/dist/hooks/frontmatter-enforcer.d.ts +24 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/index.js +294 -61
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -491,36 +491,125 @@ function buildSkillRoutingSection() {
|
|
|
491
491
|
return lines.join(`
|
|
492
492
|
`);
|
|
493
493
|
}
|
|
494
|
+
var THOTH_INTENT_GATE = `<Phase_0_Intent_Gate>
|
|
495
|
+
## Phase 0: Intent Gate (EVERY prompt)
|
|
496
|
+
|
|
497
|
+
Before ANY action, classify the incoming request:
|
|
498
|
+
|
|
499
|
+
### Step 0: Check for Skills
|
|
500
|
+
| Trigger | Skill | Action |
|
|
501
|
+
|---------|-------|--------|
|
|
502
|
+
| "Run morning boot", "Start my day" | morning-boot | Fire skill immediately |
|
|
503
|
+
| "End of day", "Close out" | evening-close | Fire skill immediately |
|
|
504
|
+
| "Dump:", "Quick thought:" | thought-router | Fire skill immediately |
|
|
505
|
+
| "Drill meeting notes" | post-meeting-drill | Fire skill immediately |
|
|
506
|
+
|
|
507
|
+
### Step 1: Identify Hemisphere(s)
|
|
508
|
+
| Signal | Hemisphere |
|
|
509
|
+
|--------|------------|
|
|
510
|
+
| Code, technical, development, bugs, features, git | **coding/** |
|
|
511
|
+
| Work, job, colleagues, projects, meetings, career, stakeholders | **work/** |
|
|
512
|
+
| Personal, health, family, friends, home, finance, feelings | **life/** |
|
|
513
|
+
| System, settings, preferences, onboarding, meta, Thoth | **kernel/** |
|
|
514
|
+
| Ambiguous or cross-domain | Multiple or ask |
|
|
515
|
+
|
|
516
|
+
### Step 2: Check Permissions
|
|
517
|
+
Before any action, verify against kernel/config/permissions.md:
|
|
518
|
+
- **Autonomous**: Read, analyze, create knowledge, fire background agents
|
|
519
|
+
- **Requires Approval**: Send communications, financial, delete, modify shared files
|
|
520
|
+
|
|
521
|
+
### Step 3: Check Trust Level
|
|
522
|
+
Read kernel/state/trust.md for current trust level:
|
|
523
|
+
- **Level 1**: Read only, all writes require approval
|
|
524
|
+
- **Level 2**: Code edits with evidence, knowledge updates
|
|
525
|
+
- **Level 3**: Routine communications, calendar changes
|
|
526
|
+
|
|
527
|
+
### Step 4: Classify Request Type
|
|
528
|
+
| Type | Signal | Action |
|
|
529
|
+
|------|--------|--------|
|
|
530
|
+
| **Information** | "What is...", "Who is...", "Tell me about..." | Retrieve context \u2192 answer |
|
|
531
|
+
| **Action** | "Send...", "Schedule...", "Create...", "Update..." | Check permissions \u2192 execute or delegate |
|
|
532
|
+
| **Planning** | "Help me plan...", "How should I..." | Retrieve context \u2192 think \u2192 propose |
|
|
533
|
+
| **Coaching** | "Reflect", "How am I doing" | Thoughtful dialogue |
|
|
534
|
+
| **Onboarding** | "Let's onboard...", "Learn about my..." | Enter onboarding mode |
|
|
535
|
+
| **Meta** | "Update your prompt", "Change how you..." | Collaborative self-modification |
|
|
536
|
+
|
|
537
|
+
### Step 5: Determine Routing
|
|
538
|
+
| Complexity | Action |
|
|
539
|
+
|------------|--------|
|
|
540
|
+
| Simple, single-hemisphere | Handle directly with context from that hemisphere |
|
|
541
|
+
| Complex, single-hemisphere | Delegate to hemisphere Master |
|
|
542
|
+
| Cross-hemisphere | Orchestrate: gather context from multiple, synthesize |
|
|
543
|
+
| Requires research | Fire parallel background_task agents |
|
|
544
|
+
</Phase_0_Intent_Gate>`;
|
|
494
545
|
var THOTH_CORE_CAPABILITIES = `<Core_Capabilities>
|
|
495
|
-
## Core Capabilities
|
|
546
|
+
## Core Capabilities (Built-In)
|
|
496
547
|
|
|
497
|
-
|
|
548
|
+
You have these capabilities built into your core function. Do NOT delegate these to sub-agents \u2014 execute them directly with full session context.
|
|
498
549
|
|
|
499
|
-
|
|
500
|
-
|-----------|--------|
|
|
501
|
-
| Simple lookup, single file read | Execute directly |
|
|
502
|
-
| Knowledge base update | Execute directly |
|
|
503
|
-
| Parallel research (multiple sources) | Fire background agents |
|
|
504
|
-
| Complex workflow with defined steps | Invoke a skill |
|
|
505
|
-
| Deep domain work requiring focus | Delegate to sub-agent |
|
|
550
|
+
### Knowledge Retrieval (You Do This Directly)
|
|
506
551
|
|
|
507
|
-
|
|
552
|
+
When Zeus asks "What do I know about X?", "Who is Y?", "Context on Z?":
|
|
508
553
|
|
|
509
|
-
|
|
554
|
+
1. **Read \`kernel/paths.json\`** to locate files
|
|
555
|
+
2. **Follow Circle System** (see Phase 1 below)
|
|
556
|
+
3. **Synthesize** the relevant information
|
|
557
|
+
4. **Cite sources** \u2014 always reference which files you found information in
|
|
558
|
+
5. **Acknowledge gaps** \u2014 if information is missing, say so
|
|
510
559
|
|
|
511
|
-
|
|
512
|
-
background_task(agent="general", prompt="[Specific task instructions]...")
|
|
513
|
-
\`\`\`
|
|
560
|
+
### Knowledge Persistence (You Do This Directly)
|
|
514
561
|
|
|
515
|
-
|
|
562
|
+
When new information emerges that should be remembered:
|
|
516
563
|
|
|
517
|
-
|
|
564
|
+
1. **Read before write** \u2014 Always check existing content first
|
|
565
|
+
2. **Smart Merge** \u2014 Integrate into existing sections, don't just append
|
|
566
|
+
3. **Use templates** from \`kernel/templates/\` for new files
|
|
567
|
+
4. **Update registries** \u2014 Add new files to relevant \`_index.md\` and \`registry.md\`
|
|
568
|
+
5. **Bidirectional links** \u2014 If A references B, add A to B's related section
|
|
569
|
+
6. **Chronicle significant events** \u2014 Append to \`chronicle.md\` with date stamp
|
|
570
|
+
7. **Frontmatter required** \u2014 Every file needs type, hemisphere, dates, tags, summary
|
|
518
571
|
|
|
519
|
-
|
|
572
|
+
### Deduplication Check (Before Creating Files)
|
|
573
|
+
|
|
574
|
+
1. Grep for entity name across knowledge base
|
|
575
|
+
2. Check if file already exists
|
|
576
|
+
3. If exists \u2192 UPDATE, not CREATE
|
|
577
|
+
4. If similar exists \u2192 ASK for clarification
|
|
520
578
|
|
|
521
|
-
|
|
579
|
+
## Functional Agents (For Specialized Tasks)
|
|
580
|
+
|
|
581
|
+
These agents handle tasks that DON'T require session context:
|
|
582
|
+
|
|
583
|
+
| Agent | Function | When to Use |
|
|
584
|
+
|-------|----------|-------------|
|
|
585
|
+
| **coach** | Reflection & thinking partner | "Help me think through X", "I'm stuck on Y", "Should I do A or B?" |
|
|
586
|
+
| **sentinel** | Proactive monitoring | "What needs my attention?", "Any overdue items?", "Check my calendar" |
|
|
587
|
+
| **diplomat** | Communication drafting | "Draft an email to X", "Help me respond to Y", "How should I say Z?" |
|
|
588
|
+
| **chronicler** | Meeting/event processing | "Process this meeting", "Extract action items" (from provided notes) |
|
|
589
|
+
|
|
590
|
+
### When to Delegate vs Execute Directly
|
|
522
591
|
|
|
523
|
-
|
|
592
|
+
| Task | Action | Why |
|
|
593
|
+
|------|--------|-----|
|
|
594
|
+
| "What do I know about Sarah?" | **Execute directly** | Needs session context for relevance |
|
|
595
|
+
| "Remember that Sarah prefers async" | **Execute directly** | Needs session context for smart merge |
|
|
596
|
+
| "Help me think through this decision" | Delegate to **coach** | Specialized coaching framework |
|
|
597
|
+
| "What needs my attention today?" | Delegate to **sentinel** | Independent calendar/task scan |
|
|
598
|
+
| "Draft an email to Sarah" | Delegate to **diplomat** | Specialized communication drafting |
|
|
599
|
+
| "Process these meeting notes" | Delegate to **chronicler** | Structured extraction from provided text |
|
|
600
|
+
|
|
601
|
+
### Background Agents (Parallel, Independent)
|
|
602
|
+
|
|
603
|
+
For parallel research or data gathering, fire background agents:
|
|
604
|
+
|
|
605
|
+
\`\`\`typescript
|
|
606
|
+
// Example: Morning boot parallel scans
|
|
607
|
+
background_task(agent="general", prompt="[Email scan instructions]...")
|
|
608
|
+
background_task(agent="general", prompt="[Calendar scan instructions]...")
|
|
609
|
+
background_task(agent="general", prompt="[Slack scan instructions]...")
|
|
610
|
+
\`\`\`
|
|
611
|
+
|
|
612
|
+
These are appropriate because they gather independent data and return facts \u2014 they don't need session context.
|
|
524
613
|
</Core_Capabilities>`;
|
|
525
614
|
var THOTH_EXECUTION = `<Execution>
|
|
526
615
|
## Execution
|
|
@@ -553,6 +642,22 @@ A task is NOT complete without evidence:
|
|
|
553
642
|
| Test run | Pass (or note pre-existing failures) |
|
|
554
643
|
| Delegation | Agent result received and verified |
|
|
555
644
|
</Execution>`;
|
|
645
|
+
var THOTH_TEMPORAL_AWARENESS = `<Temporal_Awareness>
|
|
646
|
+
## Temporal Awareness (Chronos Protocol)
|
|
647
|
+
|
|
648
|
+
Operate with deep time awareness, respecting Zeus's biological and professional cycles.
|
|
649
|
+
|
|
650
|
+
### Executive Calendar (Work)
|
|
651
|
+
- **Monday**: Launch Mode \u2014 Prioritize planning, alignment, P0 definition
|
|
652
|
+
- **Tue-Thu**: Execution Mode \u2014 Protect deep work blocks, minimize admin
|
|
653
|
+
- **Friday**: Closure Mode \u2014 Wrap up, delegation follow-ups, weekly review
|
|
654
|
+
- **Weekend**: Sanctuary \u2014 Block work unless Emergency P0
|
|
655
|
+
|
|
656
|
+
### Biological Clock (Life)
|
|
657
|
+
- **Morning (08:00-11:00)**: High Cognitive \u2014 Protect from triage hell
|
|
658
|
+
- **Afternoon (14:00-17:00)**: Collaborative \u2014 Good for meetings and emails
|
|
659
|
+
- **Evening (19:00+)**: Restoration \u2014 Block work notifications, prompt journaling
|
|
660
|
+
</Temporal_Awareness>`;
|
|
556
661
|
var THOTH_PERMISSIONS = `<Permission_System>
|
|
557
662
|
## Permission System
|
|
558
663
|
|
|
@@ -628,9 +733,11 @@ function buildThothPrompt(spec) {
|
|
|
628
733
|
if (skillRouting) {
|
|
629
734
|
sections.push(skillRouting);
|
|
630
735
|
}
|
|
736
|
+
sections.push(THOTH_INTENT_GATE);
|
|
631
737
|
sections.push(THOTH_CORE_CAPABILITIES);
|
|
632
738
|
sections.push(THOTH_EXECUTION);
|
|
633
739
|
sections.push(THOTH_PERMISSIONS);
|
|
740
|
+
sections.push(THOTH_TEMPORAL_AWARENESS);
|
|
634
741
|
sections.push(THOTH_COMMUNICATION);
|
|
635
742
|
sections.push(THOTH_CLOSING);
|
|
636
743
|
return sections.join(`
|
|
@@ -3325,9 +3432,131 @@ To proceed, mark this as Emergency/P0 or wait until work hours.`
|
|
|
3325
3432
|
getDayModeRecommendation
|
|
3326
3433
|
};
|
|
3327
3434
|
}
|
|
3435
|
+
// src/hooks/frontmatter-enforcer.ts
|
|
3436
|
+
import * as path5 from "path";
|
|
3437
|
+
var FRONTMATTER_REGEX = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
3438
|
+
function getToday() {
|
|
3439
|
+
return new Date().toISOString().split("T")[0];
|
|
3440
|
+
}
|
|
3441
|
+
function parseMarkdown(content) {
|
|
3442
|
+
const match = content.match(FRONTMATTER_REGEX);
|
|
3443
|
+
if (!match) {
|
|
3444
|
+
return { hasFrontmatter: false, frontmatter: {}, body: content };
|
|
3445
|
+
}
|
|
3446
|
+
const frontmatter = {};
|
|
3447
|
+
for (const line of match[1].split(`
|
|
3448
|
+
`)) {
|
|
3449
|
+
const colonIdx = line.indexOf(":");
|
|
3450
|
+
if (colonIdx === -1)
|
|
3451
|
+
continue;
|
|
3452
|
+
const key = line.slice(0, colonIdx).trim();
|
|
3453
|
+
let value = line.slice(colonIdx + 1).trim();
|
|
3454
|
+
if (value === "[]") {
|
|
3455
|
+
value = [];
|
|
3456
|
+
} else if (typeof value === "string") {
|
|
3457
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
3458
|
+
value = value.slice(1, -1);
|
|
3459
|
+
}
|
|
3460
|
+
}
|
|
3461
|
+
frontmatter[key] = value;
|
|
3462
|
+
}
|
|
3463
|
+
return {
|
|
3464
|
+
hasFrontmatter: true,
|
|
3465
|
+
frontmatter,
|
|
3466
|
+
body: content.slice(match[0].length)
|
|
3467
|
+
};
|
|
3468
|
+
}
|
|
3469
|
+
function serializeFrontmatter(data) {
|
|
3470
|
+
const lines = [];
|
|
3471
|
+
for (const [key, value] of Object.entries(data)) {
|
|
3472
|
+
if (Array.isArray(value)) {
|
|
3473
|
+
if (value.length === 0) {
|
|
3474
|
+
lines.push(`${key}: []`);
|
|
3475
|
+
} else {
|
|
3476
|
+
lines.push(`${key}:`);
|
|
3477
|
+
for (const item of value) {
|
|
3478
|
+
lines.push(` - ${item}`);
|
|
3479
|
+
}
|
|
3480
|
+
}
|
|
3481
|
+
} else if (typeof value === "string" && value.includes(":")) {
|
|
3482
|
+
lines.push(`${key}: "${value}"`);
|
|
3483
|
+
} else {
|
|
3484
|
+
lines.push(`${key}: ${value}`);
|
|
3485
|
+
}
|
|
3486
|
+
}
|
|
3487
|
+
return lines.join(`
|
|
3488
|
+
`);
|
|
3489
|
+
}
|
|
3490
|
+
function reconstructMarkdown(frontmatter, body) {
|
|
3491
|
+
return `---
|
|
3492
|
+
${serializeFrontmatter(frontmatter)}
|
|
3493
|
+
---
|
|
3494
|
+
|
|
3495
|
+
${body.replace(/^\n+/, "")}`;
|
|
3496
|
+
}
|
|
3497
|
+
function ensureDates(content, created, updated) {
|
|
3498
|
+
const parsed = parseMarkdown(content);
|
|
3499
|
+
if (!parsed.hasFrontmatter) {
|
|
3500
|
+
return reconstructMarkdown({ created, updated }, content);
|
|
3501
|
+
}
|
|
3502
|
+
if (!parsed.frontmatter.created) {
|
|
3503
|
+
parsed.frontmatter.created = created;
|
|
3504
|
+
}
|
|
3505
|
+
parsed.frontmatter.updated = updated;
|
|
3506
|
+
return reconstructMarkdown(parsed.frontmatter, parsed.body);
|
|
3507
|
+
}
|
|
3508
|
+
function createFrontmatterEnforcerHook(config) {
|
|
3509
|
+
const { knowledgeBasePath, enabled = true } = config;
|
|
3510
|
+
if (!enabled)
|
|
3511
|
+
return null;
|
|
3512
|
+
const kbPath = expandPath(knowledgeBasePath);
|
|
3513
|
+
const pendingEdits = new Map;
|
|
3514
|
+
function isKbMarkdownFile(filePath) {
|
|
3515
|
+
if (!filePath.endsWith(".md"))
|
|
3516
|
+
return false;
|
|
3517
|
+
return path5.resolve(filePath).startsWith(path5.resolve(kbPath));
|
|
3518
|
+
}
|
|
3519
|
+
return {
|
|
3520
|
+
"tool.execute.before": async (input, output) => {
|
|
3521
|
+
const filePath = output.args.filePath;
|
|
3522
|
+
if (!filePath || !isKbMarkdownFile(filePath))
|
|
3523
|
+
return;
|
|
3524
|
+
if (input.tool === "write") {
|
|
3525
|
+
const content = output.args.content;
|
|
3526
|
+
if (!content)
|
|
3527
|
+
return;
|
|
3528
|
+
const today = getToday();
|
|
3529
|
+
const existing = readFileSync4(filePath);
|
|
3530
|
+
const createdDate = existing ? parseMarkdown(existing).frontmatter.created || today : today;
|
|
3531
|
+
output.args.content = ensureDates(content, createdDate, today);
|
|
3532
|
+
log(`Frontmatter: dates enforced for ${path5.basename(filePath)}`);
|
|
3533
|
+
}
|
|
3534
|
+
if (input.tool === "edit" && input.callID) {
|
|
3535
|
+
pendingEdits.set(input.callID, filePath);
|
|
3536
|
+
}
|
|
3537
|
+
},
|
|
3538
|
+
"tool.execute.after": async (input, _output) => {
|
|
3539
|
+
if (input.tool !== "edit")
|
|
3540
|
+
return;
|
|
3541
|
+
const filePath = pendingEdits.get(input.callID);
|
|
3542
|
+
pendingEdits.delete(input.callID);
|
|
3543
|
+
if (!filePath)
|
|
3544
|
+
return;
|
|
3545
|
+
const content = readFileSync4(filePath);
|
|
3546
|
+
if (!content)
|
|
3547
|
+
return;
|
|
3548
|
+
const parsed = parseMarkdown(content);
|
|
3549
|
+
if (!parsed.hasFrontmatter)
|
|
3550
|
+
return;
|
|
3551
|
+
parsed.frontmatter.updated = getToday();
|
|
3552
|
+
writeFileSync2(filePath, reconstructMarkdown(parsed.frontmatter, parsed.body));
|
|
3553
|
+
log(`Frontmatter: updated timestamp for ${path5.basename(filePath)}`);
|
|
3554
|
+
}
|
|
3555
|
+
};
|
|
3556
|
+
}
|
|
3328
3557
|
// src/hooks/directory-agents-injector/index.ts
|
|
3329
3558
|
import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
|
|
3330
|
-
import { dirname as dirname4, join as join9, resolve } from "path";
|
|
3559
|
+
import { dirname as dirname4, join as join9, resolve as resolve2 } from "path";
|
|
3331
3560
|
|
|
3332
3561
|
// src/hooks/directory-agents-injector/storage.ts
|
|
3333
3562
|
import {
|
|
@@ -3397,7 +3626,7 @@ function createDirectoryAgentsInjectorHook(options) {
|
|
|
3397
3626
|
return null;
|
|
3398
3627
|
if (title.startsWith("/"))
|
|
3399
3628
|
return title;
|
|
3400
|
-
return
|
|
3629
|
+
return resolve2(directory, title);
|
|
3401
3630
|
}
|
|
3402
3631
|
function findAgentsMdUp(startDir) {
|
|
3403
3632
|
const found = [];
|
|
@@ -3449,8 +3678,8 @@ function createDirectoryAgentsInjectorHook(options) {
|
|
|
3449
3678
|
}
|
|
3450
3679
|
if (toInject.length === 0)
|
|
3451
3680
|
return;
|
|
3452
|
-
for (const { path:
|
|
3453
|
-
const relativePath =
|
|
3681
|
+
for (const { path: path6, content } of toInject) {
|
|
3682
|
+
const relativePath = path6.replace(knowledgeBasePath, "").replace(/^\//, "");
|
|
3454
3683
|
output.output += `
|
|
3455
3684
|
|
|
3456
3685
|
[Directory Context: ${relativePath}]
|
|
@@ -3537,8 +3766,8 @@ function findNearestMessageWithFields(messageDir) {
|
|
|
3537
3766
|
// src/shared-hooks/utils/logger.ts
|
|
3538
3767
|
import * as fs2 from "fs";
|
|
3539
3768
|
import * as os2 from "os";
|
|
3540
|
-
import * as
|
|
3541
|
-
var logFile =
|
|
3769
|
+
import * as path6 from "path";
|
|
3770
|
+
var logFile = path6.join(os2.tmpdir(), "thoth-plugin.log");
|
|
3542
3771
|
function log2(message, data) {
|
|
3543
3772
|
try {
|
|
3544
3773
|
const timestamp = new Date().toISOString();
|
|
@@ -5338,10 +5567,10 @@ function mergeDefs(...defs) {
|
|
|
5338
5567
|
function cloneDef(schema) {
|
|
5339
5568
|
return mergeDefs(schema._zod.def);
|
|
5340
5569
|
}
|
|
5341
|
-
function getElementAtPath(obj,
|
|
5342
|
-
if (!
|
|
5570
|
+
function getElementAtPath(obj, path7) {
|
|
5571
|
+
if (!path7)
|
|
5343
5572
|
return obj;
|
|
5344
|
-
return
|
|
5573
|
+
return path7.reduce((acc, key) => acc?.[key], obj);
|
|
5345
5574
|
}
|
|
5346
5575
|
function promiseAllObject(promisesObj) {
|
|
5347
5576
|
const keys = Object.keys(promisesObj);
|
|
@@ -5700,11 +5929,11 @@ function aborted(x, startIndex = 0) {
|
|
|
5700
5929
|
}
|
|
5701
5930
|
return false;
|
|
5702
5931
|
}
|
|
5703
|
-
function prefixIssues(
|
|
5932
|
+
function prefixIssues(path7, issues) {
|
|
5704
5933
|
return issues.map((iss) => {
|
|
5705
5934
|
var _a;
|
|
5706
5935
|
(_a = iss).path ?? (_a.path = []);
|
|
5707
|
-
iss.path.unshift(
|
|
5936
|
+
iss.path.unshift(path7);
|
|
5708
5937
|
return iss;
|
|
5709
5938
|
});
|
|
5710
5939
|
}
|
|
@@ -5872,7 +6101,7 @@ function treeifyError(error, _mapper) {
|
|
|
5872
6101
|
return issue2.message;
|
|
5873
6102
|
};
|
|
5874
6103
|
const result = { errors: [] };
|
|
5875
|
-
const processError = (error2,
|
|
6104
|
+
const processError = (error2, path7 = []) => {
|
|
5876
6105
|
var _a, _b;
|
|
5877
6106
|
for (const issue2 of error2.issues) {
|
|
5878
6107
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -5882,7 +6111,7 @@ function treeifyError(error, _mapper) {
|
|
|
5882
6111
|
} else if (issue2.code === "invalid_element") {
|
|
5883
6112
|
processError({ issues: issue2.issues }, issue2.path);
|
|
5884
6113
|
} else {
|
|
5885
|
-
const fullpath = [...
|
|
6114
|
+
const fullpath = [...path7, ...issue2.path];
|
|
5886
6115
|
if (fullpath.length === 0) {
|
|
5887
6116
|
result.errors.push(mapper(issue2));
|
|
5888
6117
|
continue;
|
|
@@ -5914,8 +6143,8 @@ function treeifyError(error, _mapper) {
|
|
|
5914
6143
|
}
|
|
5915
6144
|
function toDotPath(_path) {
|
|
5916
6145
|
const segs = [];
|
|
5917
|
-
const
|
|
5918
|
-
for (const seg of
|
|
6146
|
+
const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
6147
|
+
for (const seg of path7) {
|
|
5919
6148
|
if (typeof seg === "number")
|
|
5920
6149
|
segs.push(`[${seg}]`);
|
|
5921
6150
|
else if (typeof seg === "symbol")
|
|
@@ -16990,7 +17219,7 @@ Use \`background_output\` tool with task_id="${task.id}" to check progress:
|
|
|
16990
17219
|
});
|
|
16991
17220
|
}
|
|
16992
17221
|
function delay(ms) {
|
|
16993
|
-
return new Promise((
|
|
17222
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
16994
17223
|
}
|
|
16995
17224
|
function truncateText(text, maxLength) {
|
|
16996
17225
|
if (text.length <= maxLength)
|
|
@@ -17206,7 +17435,7 @@ Status: ${task.status}`;
|
|
|
17206
17435
|
// src/tools/skill/tools.ts
|
|
17207
17436
|
import { existsSync as existsSync11, readdirSync as readdirSync6, readFileSync as readFileSync9, lstatSync, readlinkSync } from "fs";
|
|
17208
17437
|
import { homedir as homedir5 } from "os";
|
|
17209
|
-
import { join as join17, basename as
|
|
17438
|
+
import { join as join17, basename as basename3, resolve as resolve3, dirname as dirname5 } from "path";
|
|
17210
17439
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
17211
17440
|
var __filename3 = fileURLToPath2(import.meta.url);
|
|
17212
17441
|
var __dirname3 = dirname5(__filename3);
|
|
@@ -17270,7 +17499,7 @@ function resolveSymlink(filePath) {
|
|
|
17270
17499
|
try {
|
|
17271
17500
|
const stats = lstatSync(filePath, { throwIfNoEntry: false });
|
|
17272
17501
|
if (stats?.isSymbolicLink()) {
|
|
17273
|
-
return
|
|
17502
|
+
return resolve3(filePath, "..", readlinkSync(filePath));
|
|
17274
17503
|
}
|
|
17275
17504
|
return filePath;
|
|
17276
17505
|
} catch {
|
|
@@ -17356,7 +17585,7 @@ async function parseSkillMd(skillPath) {
|
|
|
17356
17585
|
const { data, body } = parseFrontmatter(content);
|
|
17357
17586
|
const frontmatter = parseSkillFrontmatter(data);
|
|
17358
17587
|
const metadata = {
|
|
17359
|
-
name: frontmatter.name ||
|
|
17588
|
+
name: frontmatter.name || basename3(skillPath),
|
|
17360
17589
|
description: frontmatter.description,
|
|
17361
17590
|
license: frontmatter.license,
|
|
17362
17591
|
allowedTools: frontmatter["allowed-tools"],
|
|
@@ -18295,10 +18524,10 @@ function mergeDefs2(...defs) {
|
|
|
18295
18524
|
function cloneDef2(schema) {
|
|
18296
18525
|
return mergeDefs2(schema._zod.def);
|
|
18297
18526
|
}
|
|
18298
|
-
function getElementAtPath2(obj,
|
|
18299
|
-
if (!
|
|
18527
|
+
function getElementAtPath2(obj, path7) {
|
|
18528
|
+
if (!path7)
|
|
18300
18529
|
return obj;
|
|
18301
|
-
return
|
|
18530
|
+
return path7.reduce((acc, key) => acc?.[key], obj);
|
|
18302
18531
|
}
|
|
18303
18532
|
function promiseAllObject2(promisesObj) {
|
|
18304
18533
|
const keys = Object.keys(promisesObj);
|
|
@@ -18679,11 +18908,11 @@ function aborted2(x, startIndex = 0) {
|
|
|
18679
18908
|
}
|
|
18680
18909
|
return false;
|
|
18681
18910
|
}
|
|
18682
|
-
function prefixIssues2(
|
|
18911
|
+
function prefixIssues2(path7, issues) {
|
|
18683
18912
|
return issues.map((iss) => {
|
|
18684
18913
|
var _a;
|
|
18685
18914
|
(_a = iss).path ?? (_a.path = []);
|
|
18686
|
-
iss.path.unshift(
|
|
18915
|
+
iss.path.unshift(path7);
|
|
18687
18916
|
return iss;
|
|
18688
18917
|
});
|
|
18689
18918
|
}
|
|
@@ -18866,7 +19095,7 @@ function formatError2(error45, mapper = (issue3) => issue3.message) {
|
|
|
18866
19095
|
}
|
|
18867
19096
|
function treeifyError2(error45, mapper = (issue3) => issue3.message) {
|
|
18868
19097
|
const result = { errors: [] };
|
|
18869
|
-
const processError = (error46,
|
|
19098
|
+
const processError = (error46, path7 = []) => {
|
|
18870
19099
|
var _a, _b;
|
|
18871
19100
|
for (const issue3 of error46.issues) {
|
|
18872
19101
|
if (issue3.code === "invalid_union" && issue3.errors.length) {
|
|
@@ -18876,7 +19105,7 @@ function treeifyError2(error45, mapper = (issue3) => issue3.message) {
|
|
|
18876
19105
|
} else if (issue3.code === "invalid_element") {
|
|
18877
19106
|
processError({ issues: issue3.issues }, issue3.path);
|
|
18878
19107
|
} else {
|
|
18879
|
-
const fullpath = [...
|
|
19108
|
+
const fullpath = [...path7, ...issue3.path];
|
|
18880
19109
|
if (fullpath.length === 0) {
|
|
18881
19110
|
result.errors.push(mapper(issue3));
|
|
18882
19111
|
continue;
|
|
@@ -18908,8 +19137,8 @@ function treeifyError2(error45, mapper = (issue3) => issue3.message) {
|
|
|
18908
19137
|
}
|
|
18909
19138
|
function toDotPath2(_path) {
|
|
18910
19139
|
const segs = [];
|
|
18911
|
-
const
|
|
18912
|
-
for (const seg of
|
|
19140
|
+
const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
19141
|
+
for (const seg of path7) {
|
|
18913
19142
|
if (typeof seg === "number")
|
|
18914
19143
|
segs.push(`[${seg}]`);
|
|
18915
19144
|
else if (typeof seg === "symbol")
|
|
@@ -30656,13 +30885,13 @@ function resolveRef(ref, ctx) {
|
|
|
30656
30885
|
if (!ref.startsWith("#")) {
|
|
30657
30886
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
30658
30887
|
}
|
|
30659
|
-
const
|
|
30660
|
-
if (
|
|
30888
|
+
const path7 = ref.slice(1).split("/").filter(Boolean);
|
|
30889
|
+
if (path7.length === 0) {
|
|
30661
30890
|
return ctx.rootSchema;
|
|
30662
30891
|
}
|
|
30663
30892
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
30664
|
-
if (
|
|
30665
|
-
const key =
|
|
30893
|
+
if (path7[0] === defsKey) {
|
|
30894
|
+
const key = path7[1];
|
|
30666
30895
|
if (!key || !ctx.defs[key]) {
|
|
30667
30896
|
throw new Error(`Reference not found: ${ref}`);
|
|
30668
30897
|
}
|
|
@@ -31076,6 +31305,7 @@ var HooksConfigSchema = exports_external2.object({
|
|
|
31076
31305
|
"temporal-awareness": exports_external2.boolean().optional(),
|
|
31077
31306
|
"knowledge-persistence": exports_external2.boolean().optional(),
|
|
31078
31307
|
"directory-agents-injector": exports_external2.boolean().optional(),
|
|
31308
|
+
"frontmatter-enforcer": exports_external2.boolean().optional(),
|
|
31079
31309
|
"todo-continuation": exports_external2.boolean().optional(),
|
|
31080
31310
|
"session-recovery": exports_external2.boolean().optional(),
|
|
31081
31311
|
"context-window-monitor": exports_external2.boolean().optional(),
|
|
@@ -31113,7 +31343,7 @@ var ThothPluginConfigSchema = exports_external2.object({
|
|
|
31113
31343
|
}).strict();
|
|
31114
31344
|
// src/index.ts
|
|
31115
31345
|
import * as fs3 from "fs";
|
|
31116
|
-
import * as
|
|
31346
|
+
import * as path7 from "path";
|
|
31117
31347
|
var sessionSpecializations = new Map;
|
|
31118
31348
|
function loadConfigFromPath(configPath) {
|
|
31119
31349
|
try {
|
|
@@ -31145,8 +31375,8 @@ function mergeConfigs(base, override) {
|
|
|
31145
31375
|
};
|
|
31146
31376
|
}
|
|
31147
31377
|
function loadPluginConfig(directory) {
|
|
31148
|
-
const userConfigPath =
|
|
31149
|
-
const projectConfigPath =
|
|
31378
|
+
const userConfigPath = path7.join(getUserConfigDir(), "opencode", "thoth-plugin.json");
|
|
31379
|
+
const projectConfigPath = path7.join(directory, ".opencode", "thoth-plugin.json");
|
|
31150
31380
|
let config3 = loadConfigFromPath(userConfigPath) ?? {};
|
|
31151
31381
|
const projectConfig = loadConfigFromPath(projectConfigPath);
|
|
31152
31382
|
if (projectConfig) {
|
|
@@ -31160,15 +31390,15 @@ function resolveKnowledgeBasePath(config3, directory) {
|
|
|
31160
31390
|
return expandPath(config3.knowledge_base);
|
|
31161
31391
|
}
|
|
31162
31392
|
const commonLocations = [
|
|
31163
|
-
|
|
31164
|
-
|
|
31165
|
-
|
|
31166
|
-
|
|
31167
|
-
|
|
31168
|
-
|
|
31393
|
+
path7.join(process.env.HOME || "", "Repos", "thoth"),
|
|
31394
|
+
path7.join(process.env.HOME || "", "repos", "thoth"),
|
|
31395
|
+
path7.join(process.env.HOME || "", "Projects", "thoth"),
|
|
31396
|
+
path7.join(process.env.HOME || "", "projects", "thoth"),
|
|
31397
|
+
path7.join(process.env.HOME || "", "thoth"),
|
|
31398
|
+
path7.join(directory, "thoth")
|
|
31169
31399
|
];
|
|
31170
31400
|
for (const location of commonLocations) {
|
|
31171
|
-
const kernelPath =
|
|
31401
|
+
const kernelPath = path7.join(location, "kernel");
|
|
31172
31402
|
if (fs3.existsSync(kernelPath)) {
|
|
31173
31403
|
log(`Found knowledge base at: ${location}`);
|
|
31174
31404
|
return location;
|
|
@@ -31189,6 +31419,7 @@ var ThothPlugin = async (ctx) => {
|
|
|
31189
31419
|
const trustLevelTracker = hooksConfig["trust-level-tracker"] !== false ? createTrustLevelTrackerHook({ knowledgeBasePath }) : null;
|
|
31190
31420
|
const contextAperture = hooksConfig["context-aperture"] !== false ? createContextApertureHook({ knowledgeBasePath }) : null;
|
|
31191
31421
|
const temporalAwareness = hooksConfig["temporal-awareness"] !== false ? createTemporalAwarenessHook() : null;
|
|
31422
|
+
const frontmatterEnforcer = hooksConfig["frontmatter-enforcer"] !== false ? createFrontmatterEnforcerHook({ knowledgeBasePath }) : null;
|
|
31192
31423
|
const todoContinuationEnforcer = hooksConfig["todo-continuation"] !== false ? createTodoContinuationEnforcer(ctx) : null;
|
|
31193
31424
|
const sessionRecoveryHook = hooksConfig["session-recovery"] !== false ? createSessionRecoveryHook(ctx, { experimental: { auto_resume: true } }) : null;
|
|
31194
31425
|
const contextWindowMonitor = hooksConfig["context-window-monitor"] !== false ? createContextWindowMonitorHook(ctx) : null;
|
|
@@ -31293,10 +31524,12 @@ var ThothPlugin = async (ctx) => {
|
|
|
31293
31524
|
await temporalAwareness?.["tool.execute.before"]?.(input, output);
|
|
31294
31525
|
await contextAperture?.["tool.execute.before"]?.(input, output);
|
|
31295
31526
|
await trustLevelTracker?.["tool.execute.before"]?.(input, output);
|
|
31527
|
+
await frontmatterEnforcer?.["tool.execute.before"]?.(input, output);
|
|
31296
31528
|
},
|
|
31297
31529
|
"tool.execute.after": async (input, output) => {
|
|
31298
31530
|
await trustLevelTracker?.["tool.execute.after"]?.(input, output);
|
|
31299
31531
|
await contextAperture?.["tool.execute.after"]?.(input, output);
|
|
31532
|
+
await frontmatterEnforcer?.["tool.execute.after"]?.(input, output);
|
|
31300
31533
|
await directoryAgentsInjector?.["tool.execute.after"]?.(input, output);
|
|
31301
31534
|
await contextWindowMonitor?.["tool.execute.after"]?.(input, output);
|
|
31302
31535
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thoth-plugin",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Thoth - Root-level life orchestrator for OpenCode. Unified AI chief of staff combining Sisyphus execution quality, Personal-OS rhythms, and Thoth relationship model.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|