@wrongstack/core 0.9.1 → 0.9.7

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 (44) hide show
  1. package/dist/{agent-subagent-runner-R0I0Xusn.d.ts → agent-subagent-runner-DaF_EgRG.d.ts} +1 -1
  2. package/dist/{config-DoUAEvXH.d.ts → config-SkMIDN9L.d.ts} +15 -1
  3. package/dist/coordination/index.d.ts +6 -6
  4. package/dist/defaults/index.d.ts +9 -9
  5. package/dist/execution/index.d.ts +6 -6
  6. package/dist/extension/index.d.ts +2 -2
  7. package/dist/{index-u2ROAV0F.d.ts → index-Bsha5K4D.d.ts} +1 -1
  8. package/dist/{index-bOl8lzFV.d.ts → index-CP8638Wm.d.ts} +1 -1
  9. package/dist/index.d.ts +129 -20
  10. package/dist/index.js +1474 -57
  11. package/dist/index.js.map +1 -1
  12. package/dist/infrastructure/index.d.ts +2 -2
  13. package/dist/kernel/index.d.ts +2 -2
  14. package/dist/{mcp-servers-jEoMIBZv.d.ts → mcp-servers-BouUWYW6.d.ts} +1 -1
  15. package/dist/{multi-agent-coordinator-COwCGIrU.d.ts → multi-agent-coordinator-DTXF2aAl.d.ts} +1 -1
  16. package/dist/{null-fleet-bus-C1grTnOF.d.ts → null-fleet-bus-Chrc_3Pp.d.ts} +2 -2
  17. package/dist/{plan-templates-ByT1HcRI.d.ts → plan-templates-envSmNlZ.d.ts} +2 -2
  18. package/dist/sdd/index.d.ts +3 -3
  19. package/dist/storage/index.d.ts +74 -5
  20. package/dist/storage/index.js +352 -5
  21. package/dist/storage/index.js.map +1 -1
  22. package/dist/{tool-executor-D7a00JVJ.d.ts → tool-executor-CsktM3h9.d.ts} +1 -1
  23. package/dist/types/index.d.ts +3 -3
  24. package/dist/utils/index.d.ts +1 -1
  25. package/dist/utils/index.js +3 -1
  26. package/dist/utils/index.js.map +1 -1
  27. package/dist/{wstack-paths-CJYrjQU8.d.ts → wstack-paths-BCgmTNlG.d.ts} +4 -0
  28. package/package.json +1 -1
  29. package/skills/api-design/SKILL.md +139 -0
  30. package/skills/audit-log/SKILL.md +87 -14
  31. package/skills/bug-hunter/SKILL.md +42 -19
  32. package/skills/docker-deploy/SKILL.md +155 -0
  33. package/skills/git-flow/SKILL.md +53 -1
  34. package/skills/multi-agent/SKILL.md +42 -0
  35. package/skills/node-modern/SKILL.md +57 -1
  36. package/skills/observability/SKILL.md +134 -0
  37. package/skills/prompt-engineering/SKILL.md +46 -19
  38. package/skills/react-modern/SKILL.md +92 -1
  39. package/skills/refactor-planner/SKILL.md +49 -1
  40. package/skills/sdd/SKILL.md +12 -1
  41. package/skills/security-scanner/SKILL.md +46 -1
  42. package/skills/skill-creator/SKILL.md +49 -52
  43. package/skills/testing/SKILL.md +170 -0
  44. package/skills/typescript-strict/SKILL.md +98 -1
@@ -1,10 +1,10 @@
1
1
  export { D as DefaultLogger, a as DefaultLoggerOptions } from '../logger-bOzkF5LL.js';
2
2
  export { D as DefaultPathResolver, a as DefaultTokenCounter } from '../path-resolver-TcJfc29Y.js';
3
- export { C as ContextManagerAction, a as ContextManagerInput, b as ContextManagerResult, c as ContextManagerToolOptions, d as allServers, e as awsServer, f as blockServer, g as braveSearchServer, h as context7Server, i as contextManagerTool, j as createContextManagerTool, k as everArtServer, l as filesystemServer, m as githubServer, n as googleMapsServer, o as miniMaxVisionServer, s as sentinelServer, p as slackServer, z as zaiVisionServer } from '../mcp-servers-jEoMIBZv.js';
3
+ export { C as ContextManagerAction, a as ContextManagerInput, b as ContextManagerResult, c as ContextManagerToolOptions, d as allServers, e as awsServer, f as blockServer, g as braveSearchServer, h as context7Server, i as contextManagerTool, j as createContextManagerTool, k as everArtServer, l as filesystemServer, m as githubServer, n as googleMapsServer, o as miniMaxVisionServer, s as sentinelServer, p as slackServer, z as zaiVisionServer } from '../mcp-servers-BouUWYW6.js';
4
4
  import '../logger-DDd5C--Z.js';
5
5
  import '../events-CiG9qUM_.js';
6
6
  import '../context-BRNbHmRM.js';
7
7
  import '../models-registry-BcYJDKLm.js';
8
8
  import '../path-resolver-CPRj4bFY.js';
9
9
  import '../compactor-DVTKL7XD.js';
10
- import '../config-DoUAEvXH.js';
10
+ import '../config-SkMIDN9L.js';
@@ -1,9 +1,9 @@
1
1
  export { B as BindOptions, C as Container, D as Decorator, F as Factory, M as Middleware, b as MiddlewareHandler, N as NextFn, P as Pipeline, d as PipelineOptions, T as Token } from '../system-prompt-Bs-Wliab.js';
2
2
  export { E as EventBus, a as EventLogger, b as EventMap, c as EventName, L as Listener, S as ScopedEventBus } from '../events-CiG9qUM_.js';
3
- export { R as RunController, b as RunControllerOptions, T as TOKENS } from '../index-u2ROAV0F.js';
3
+ export { R as RunController, b as RunControllerOptions, T as TOKENS } from '../index-Bsha5K4D.js';
4
4
  import '../context-BRNbHmRM.js';
5
5
  import '../compactor-DVTKL7XD.js';
6
- import '../config-DoUAEvXH.js';
6
+ import '../config-SkMIDN9L.js';
7
7
  import '../models-registry-BcYJDKLm.js';
8
8
  import '../retry-policy-BYkq0ugs.js';
9
9
  import '../input-reader-E-ffP2ee.js';
@@ -1,6 +1,6 @@
1
1
  import { a as Compactor } from './compactor-DVTKL7XD.js';
2
2
  import { M as Message, Q as Tool } from './context-BRNbHmRM.js';
3
- import { M as MCPServerConfig } from './config-DoUAEvXH.js';
3
+ import { M as MCPServerConfig } from './config-SkMIDN9L.js';
4
4
 
5
5
  type ContextManagerAction = 'check' | 'summary' | 'prune' | 'add_note' | 'compact' | 'repair';
6
6
  interface ContextManagerInput {
@@ -1,5 +1,5 @@
1
1
  import { n as SubagentConfig, l as MultiAgentCoordinator, M as MultiAgentConfig, t as SubagentRunner, S as SpawnResult, v as TaskSpec, B as BridgeMessage, A as AgentBridge, k as CoordinatorStatus, u as TaskResult } from './multi-agent-3ZnTB1aT.js';
2
- import { F as FleetBus } from './agent-subagent-runner-R0I0Xusn.js';
2
+ import { F as FleetBus } from './agent-subagent-runner-DaF_EgRG.js';
3
3
  import { EventEmitter } from 'node:events';
4
4
 
5
5
  /**
@@ -1,9 +1,9 @@
1
- import { c as AgentPhase, b as AgentDefinition, d as DefaultMultiAgentCoordinator, f as DispatchClassifier } from './multi-agent-coordinator-COwCGIrU.js';
1
+ import { c as AgentPhase, b as AgentDefinition, d as DefaultMultiAgentCoordinator, f as DispatchClassifier } from './multi-agent-coordinator-DTXF2aAl.js';
2
2
  import { n as SubagentConfig, u as TaskResult, k as CoordinatorStatus, v as TaskSpec, M as MultiAgentConfig, t as SubagentRunner } from './multi-agent-3ZnTB1aT.js';
3
3
  import { B as SessionWriter, Q as Tool, y as SessionStore } from './context-BRNbHmRM.js';
4
4
  import { a as DirectorStateSnapshot } from './director-state-BmYi3DGA.js';
5
5
  import { I as InMemoryAgentBridge } from './agent-bridge-DMVOX0cF.js';
6
- import { F as FleetBus, e as FleetUsage, f as FleetUsageAggregator } from './agent-subagent-runner-R0I0Xusn.js';
6
+ import { F as FleetBus, e as FleetUsage, f as FleetUsageAggregator } from './agent-subagent-runner-DaF_EgRG.js';
7
7
  import { E as EventBus } from './events-CiG9qUM_.js';
8
8
 
9
9
  /**
@@ -2,8 +2,8 @@ import { E as EventBus } from './events-CiG9qUM_.js';
2
2
  import { y as SessionStore, x as SessionMetadata, B as SessionWriter, r as ResumedSession, S as SessionData, z as SessionSummary, c as ContentBlock, w as SessionEvent, N as TodoItem, f as ConversationState } from './context-BRNbHmRM.js';
3
3
  import { e as AttachmentStore, A as AddAttachmentInput, d as AttachmentRef, a as Attachment } from './session-reader-CSWcb5Ga.js';
4
4
  import { b as MemoryStore, a as MemoryScope } from './memory-CEXuo7sz.js';
5
- import { a as WstackPaths } from './wstack-paths-CJYrjQU8.js';
6
- import { c as ConfigStore, a as Config, b as ConfigLoader } from './config-DoUAEvXH.js';
5
+ import { a as WstackPaths } from './wstack-paths-BCgmTNlG.js';
6
+ import { c as ConfigStore, a as Config, b as ConfigLoader } from './config-SkMIDN9L.js';
7
7
  import { S as SecretVault } from './secret-vault-DoISxaKO.js';
8
8
 
9
9
  interface SessionStoreOptions {
@@ -1,14 +1,14 @@
1
1
  import { h as Specification, S as SpecAnalysis, g as SpecValidationResult, l as TaskGraph, m as TaskNode, k as TaskFilter, p as TaskSort, o as TaskProgress, r as TaskType, n as TaskPriority, e as SpecStatus, f as SpecTemplate, b as SpecRequirement } from '../task-graph-D1YQbpxF.js';
2
2
  import { E as EventBus } from '../events-CiG9qUM_.js';
3
3
  import { D as DoneCondition, u as TaskResult } from '../multi-agent-3ZnTB1aT.js';
4
- import { c as Agent } from '../index-bOl8lzFV.js';
5
- import { A as AgentFactory } from '../agent-subagent-runner-R0I0Xusn.js';
4
+ import { c as Agent } from '../index-CP8638Wm.js';
5
+ import { A as AgentFactory } from '../agent-subagent-runner-DaF_EgRG.js';
6
6
  import '../context-BRNbHmRM.js';
7
7
  import '../logger-DDd5C--Z.js';
8
8
  import '../system-prompt-Bs-Wliab.js';
9
9
  import '../observability-BhnVLBLS.js';
10
10
  import '../secret-scrubber-DttNiGYA.js';
11
- import '../config-DoUAEvXH.js';
11
+ import '../config-SkMIDN9L.js';
12
12
  import '../models-registry-BcYJDKLm.js';
13
13
 
14
14
  declare class SpecParser {
@@ -1,15 +1,15 @@
1
- export { A as AbandonedSession, a as AttachmentStoreOptions, C as ConfigLoaderOptions, b as ConfigMigration, c as ConfigMigrationError, d as ConfigSource, D as DEFAULT_CONFIG_MIGRATIONS, e as DefaultAttachmentStore, f as DefaultConfigLoader, g as DefaultConfigStore, h as DefaultMemoryStore, i as DefaultSessionStore, M as MemoryStoreOptions, j as MigrationContext, k as MigrationResult, P as PersistedQueueItem, l as PlanFile, m as PlanItem, n as PlanTemplate, Q as QueueStore, R as RecoveryLock, o as RecoveryLockOptions, S as SessionAnalyzer, p as SessionStoreOptions, T as TodosCheckpointFile, q as addPlanItem, r as attachPlanCheckpoint, s as attachTodosCheckpoint, t as clearPlan, u as deriveTodosFromPlanItem, v as emptyPlan, w as formatPlan, x as formatPlanTemplates, y as getPlanTemplate, z as listPlanTemplates, B as loadPlan, E as loadTodosCheckpoint, F as removePlanItem, G as runConfigMigrations, H as savePlan, I as saveTodosCheckpoint, J as setPlanItemStatus } from '../plan-templates-ByT1HcRI.js';
1
+ export { A as AbandonedSession, a as AttachmentStoreOptions, C as ConfigLoaderOptions, b as ConfigMigration, c as ConfigMigrationError, d as ConfigSource, D as DEFAULT_CONFIG_MIGRATIONS, e as DefaultAttachmentStore, f as DefaultConfigLoader, g as DefaultConfigStore, h as DefaultMemoryStore, i as DefaultSessionStore, M as MemoryStoreOptions, j as MigrationContext, k as MigrationResult, P as PersistedQueueItem, l as PlanFile, m as PlanItem, n as PlanTemplate, Q as QueueStore, R as RecoveryLock, o as RecoveryLockOptions, S as SessionAnalyzer, p as SessionStoreOptions, T as TodosCheckpointFile, q as addPlanItem, r as attachPlanCheckpoint, s as attachTodosCheckpoint, t as clearPlan, u as deriveTodosFromPlanItem, v as emptyPlan, w as formatPlan, x as formatPlanTemplates, y as getPlanTemplate, z as listPlanTemplates, B as loadPlan, E as loadTodosCheckpoint, F as removePlanItem, G as runConfigMigrations, H as savePlan, I as saveTodosCheckpoint, J as setPlanItemStatus } from '../plan-templates-envSmNlZ.js';
2
2
  export { D as DefaultSessionReader } from '../session-reader-CSWcb5Ga.js';
3
3
  import { S as SessionRewinder, C as CheckpointInfo, a as RewindResultExtended } from '../session-rewinder-C9HnMkhP.js';
4
4
  export { D as DirectorStateCheckpoint, a as DirectorStateSnapshot, b as DirectorSubagentState, c as DirectorTaskState, l as loadDirectorState } from '../director-state-BmYi3DGA.js';
5
5
  export { G as GoalFile, J as JournalEntry, M as MAX_JOURNAL_ENTRIES, a as appendJournal, e as emptyGoal, f as formatGoal, g as goalFilePath, l as loadGoal, s as saveGoal, b as summarizeUsage } from '../goal-store-C7jcumEh.js';
6
+ import { a as WstackPaths } from '../wstack-paths-BCgmTNlG.js';
7
+ import { S as SyncCategory, m as SyncConfig } from '../config-SkMIDN9L.js';
6
8
  import '../events-CiG9qUM_.js';
7
9
  import '../context-BRNbHmRM.js';
8
10
  import '../memory-CEXuo7sz.js';
9
- import '../wstack-paths-CJYrjQU8.js';
10
- import '../config-DoUAEvXH.js';
11
- import '../models-registry-BcYJDKLm.js';
12
11
  import '../secret-vault-DoISxaKO.js';
12
+ import '../models-registry-BcYJDKLm.js';
13
13
 
14
14
  interface SessionRewinderOptions {
15
15
  sessionsDir: string;
@@ -30,4 +30,73 @@ declare class DefaultSessionRewinder implements SessionRewinder {
30
30
  rewindToStart(sessionId: string): Promise<RewindResultExtended>;
31
31
  }
32
32
 
33
- export { DefaultSessionRewinder, type SessionRewinderOptions };
33
+ interface PromptEntry {
34
+ id: string;
35
+ title: string;
36
+ content: string;
37
+ tags: string[];
38
+ createdAt: string;
39
+ updatedAt: string;
40
+ }
41
+ interface PromptStore {
42
+ list(): Promise<PromptEntry[]>;
43
+ get(id: string): Promise<PromptEntry | null>;
44
+ save(entry: PromptEntry): Promise<void>;
45
+ delete(id: string): Promise<boolean>;
46
+ find(query: string): Promise<PromptEntry[]>;
47
+ }
48
+ declare class DefaultPromptStore implements PromptStore {
49
+ private readonly dir;
50
+ constructor(paths: WstackPaths);
51
+ list(): Promise<PromptEntry[]>;
52
+ get(id: string): Promise<PromptEntry | null>;
53
+ save(entry: PromptEntry): Promise<void>;
54
+ delete(id: string): Promise<boolean>;
55
+ find(query: string): Promise<PromptEntry[]>;
56
+ /** Create a new entry and return it. Does NOT persist — call save() afterwards. */
57
+ createNew(title: string, content: string, tags?: string[]): PromptEntry;
58
+ }
59
+
60
+ declare const ALL_SYNC_CATEGORIES: SyncCategory[];
61
+ interface SyncResult {
62
+ ok: boolean;
63
+ action: 'push' | 'pull';
64
+ categories: SyncCategory[];
65
+ committedAt?: string;
66
+ message: string;
67
+ }
68
+ /**
69
+ * CloudSync — push/pull user-selected ~/.wrongstack categories to a
70
+ * private GitHub repo. No git CLI needed; uses GitHub REST API via fetch.
71
+ * The token is stored encrypted via SecretVault (field named `githubToken`
72
+ * so the vault walker picks it up automatically).
73
+ */
74
+ declare class CloudSync {
75
+ private readonly paths;
76
+ private readonly getConfig;
77
+ private readonly setConfig;
78
+ private readonly statePath;
79
+ private state;
80
+ constructor(paths: WstackPaths, getConfig: () => SyncConfig | null, setConfig: (c: SyncConfig) => Promise<void>);
81
+ status(): Promise<string>;
82
+ enable(_repo: string, _categories: SyncCategory[]): Promise<string>;
83
+ disable(): Promise<string>;
84
+ push(token: string): Promise<SyncResult>;
85
+ pull(token: string): Promise<SyncResult>;
86
+ hasLocalChanges(): Promise<boolean>;
87
+ loadState(): Promise<void>;
88
+ private githubFetch;
89
+ private getRef;
90
+ private updateRef;
91
+ private getCommit;
92
+ private getTreeEntries;
93
+ private createCommit;
94
+ private createGitTree;
95
+ private getBlob;
96
+ private buildLocalTree;
97
+ private hashLocalCategories;
98
+ private categoryToPath;
99
+ private walkDir;
100
+ }
101
+
102
+ export { ALL_SYNC_CATEGORIES, CloudSync, DefaultPromptStore, DefaultSessionRewinder, type PromptEntry, type PromptStore, type SessionRewinderOptions, SyncCategory, SyncConfig, type SyncResult };
@@ -30,8 +30,8 @@ async function atomicWrite(targetPath, content, opts = {}) {
30
30
  }
31
31
  let mode;
32
32
  try {
33
- const stat3 = await fsp.stat(targetPath);
34
- mode = stat3.mode & 511;
33
+ const stat4 = await fsp.stat(targetPath);
34
+ mode = stat4.mode & 511;
35
35
  } catch {
36
36
  mode = opts.mode;
37
37
  }
@@ -291,8 +291,8 @@ var DefaultSessionStore = class {
291
291
  return JSON.parse(raw);
292
292
  } catch {
293
293
  const full = this.sessionPath(id, ".jsonl");
294
- const stat3 = await fsp.stat(full);
295
- const summary = await this.summarize(id, stat3.mtime.toISOString());
294
+ const stat4 = await fsp.stat(full);
295
+ const summary = await this.summarize(id, stat4.mtime.toISOString());
296
296
  await atomicWrite(manifest, JSON.stringify(summary), { mode: 384 }).catch((err) => {
297
297
  console.warn(
298
298
  `[session-store] Failed to write manifest for "${id}":`,
@@ -2778,7 +2778,354 @@ function formatGoal(goal, journalLimit = 10) {
2778
2778
  }
2779
2779
  return lines.join("\n");
2780
2780
  }
2781
+ var DefaultPromptStore = class {
2782
+ dir;
2783
+ constructor(paths) {
2784
+ this.dir = paths.globalPrompts;
2785
+ }
2786
+ async list() {
2787
+ await ensureDir(this.dir);
2788
+ let entries = [];
2789
+ try {
2790
+ const files = await fsp.readdir(this.dir);
2791
+ for (const file of files) {
2792
+ if (!file.endsWith(".json")) continue;
2793
+ try {
2794
+ const raw = JSON.parse(
2795
+ await fsp.readFile(path7.join(this.dir, file), "utf8")
2796
+ );
2797
+ entries.push(raw.entry);
2798
+ } catch {
2799
+ }
2800
+ }
2801
+ } catch {
2802
+ }
2803
+ return entries.sort(
2804
+ (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
2805
+ );
2806
+ }
2807
+ async get(id) {
2808
+ const file = path7.join(this.dir, `${id}.json`);
2809
+ try {
2810
+ const raw = JSON.parse(await fsp.readFile(file, "utf8"));
2811
+ return raw.entry;
2812
+ } catch {
2813
+ return null;
2814
+ }
2815
+ }
2816
+ async save(entry) {
2817
+ await ensureDir(this.dir);
2818
+ const file = path7.join(this.dir, `${entry.id}.json`);
2819
+ const raw = { version: 1, entry };
2820
+ await atomicWrite(file, JSON.stringify(raw, null, 2));
2821
+ }
2822
+ async delete(id) {
2823
+ const file = path7.join(this.dir, `${id}.json`);
2824
+ try {
2825
+ await fsp.unlink(file);
2826
+ return true;
2827
+ } catch {
2828
+ return false;
2829
+ }
2830
+ }
2831
+ async find(query) {
2832
+ const all = await this.list();
2833
+ const lower = query.toLowerCase();
2834
+ return all.filter(
2835
+ (e) => e.title.toLowerCase().includes(lower) || e.content.toLowerCase().includes(lower) || e.tags.some((t) => t.toLowerCase().includes(lower))
2836
+ );
2837
+ }
2838
+ /** Create a new entry and return it. Does NOT persist — call save() afterwards. */
2839
+ createNew(title, content, tags = []) {
2840
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2841
+ return {
2842
+ id: randomUUID().slice(0, 8),
2843
+ title,
2844
+ content,
2845
+ tags,
2846
+ createdAt: now,
2847
+ updatedAt: now
2848
+ };
2849
+ }
2850
+ };
2851
+ var ALL_SYNC_CATEGORIES = ["settings", "skills", "prompts", "memory", "history"];
2852
+ var CloudSync = class {
2853
+ constructor(paths, getConfig, setConfig) {
2854
+ this.paths = paths;
2855
+ this.getConfig = getConfig;
2856
+ this.setConfig = setConfig;
2857
+ this.statePath = path7.join(paths.globalRoot, "sync-state.json");
2858
+ }
2859
+ paths;
2860
+ getConfig;
2861
+ setConfig;
2862
+ statePath;
2863
+ state = null;
2864
+ // ── Public API ─────────────────────────────────────────────────────
2865
+ async status() {
2866
+ const cfg = this.getConfig();
2867
+ if (!cfg?.enabled) {
2868
+ return "CloudSync: disabled. Run `/sync enable` to activate.";
2869
+ }
2870
+ const last = this.state?.lastSyncedAt;
2871
+ const since = last ? timeAgo(last) : "never";
2872
+ return [
2873
+ `CloudSync: enabled`,
2874
+ ` repo: ${cfg.repo}`,
2875
+ ` categories: ${cfg.categories.join(", ")}`,
2876
+ ` last sync: ${since}`
2877
+ ].join("\n");
2878
+ }
2879
+ async enable(_repo, _categories) {
2880
+ return "Enable via /sync enable.";
2881
+ }
2882
+ async disable() {
2883
+ const cfg = this.getConfig();
2884
+ if (!cfg) return "CloudSync is not configured.";
2885
+ const next = { ...cfg, enabled: false };
2886
+ await this.setConfig(next);
2887
+ return "CloudSync disabled. Local data kept.";
2888
+ }
2889
+ async push(token) {
2890
+ const cfg = this.getConfig();
2891
+ if (!cfg?.enabled) return { ok: false, action: "push", categories: [], message: "Not enabled." };
2892
+ const parts = cfg.repo.split("/");
2893
+ const owner = parts[0];
2894
+ const repoName = parts[1];
2895
+ const branch = "main";
2896
+ const baseTreeSha = this.state?.sha;
2897
+ const { treeEntries, rev } = await this.buildLocalTree(cfg.categories);
2898
+ const newTreeSha = await this.createGitTree(token, owner, repoName, treeEntries, baseTreeSha);
2899
+ const commitSha = await this.createCommit(
2900
+ token,
2901
+ owner,
2902
+ repoName,
2903
+ newTreeSha,
2904
+ baseTreeSha,
2905
+ `Sync ${cfg.categories.join(", ")} \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`
2906
+ );
2907
+ await this.updateRef(token, owner, repoName, branch, commitSha);
2908
+ const syncState = {
2909
+ version: 1,
2910
+ sha: commitSha,
2911
+ lastSyncedAt: (/* @__PURE__ */ new Date()).toISOString(),
2912
+ localRev: rev
2913
+ };
2914
+ await fsp.writeFile(this.statePath, JSON.stringify(syncState, null, 2), "utf8");
2915
+ this.state = syncState;
2916
+ return {
2917
+ ok: true,
2918
+ action: "push",
2919
+ categories: cfg.categories,
2920
+ committedAt: commitSha,
2921
+ message: `Pushed ${cfg.categories.join(", ")} to ${cfg.repo}. Commit: ${commitSha.slice(0, 7)}`
2922
+ };
2923
+ }
2924
+ async pull(token) {
2925
+ const cfg = this.getConfig();
2926
+ if (!cfg?.enabled) return { ok: false, action: "pull", categories: [], message: "Not enabled." };
2927
+ const pullParts = cfg.repo.split("/");
2928
+ const owner = pullParts[0];
2929
+ const repoName = pullParts[1];
2930
+ const branchData = await this.getRef(token, owner, repoName, "main");
2931
+ const currentSha = branchData.object.sha;
2932
+ const commitData = await this.getCommit(token, owner, repoName, currentSha);
2933
+ const treeSha = commitData.tree.sha;
2934
+ const treeEntries = await this.getTreeEntries(token, owner, repoName, treeSha);
2935
+ for (const entry of treeEntries) {
2936
+ if (entry.type !== "blob") continue;
2937
+ const segments = entry.path.split("/");
2938
+ if (segments[0] !== "data" || !segments[1]) continue;
2939
+ const cat = segments[1];
2940
+ if (!["settings", "skills", "prompts", "memory", "history"].includes(cat)) continue;
2941
+ const localPath = this.categoryToPath(cat);
2942
+ if (!localPath) continue;
2943
+ const rel = segments.slice(2).join("/");
2944
+ const destPath = rel ? path7.join(localPath, rel) : localPath;
2945
+ const blobData = await this.getBlob(token, owner, repoName, entry.sha);
2946
+ await fsp.mkdir(path7.dirname(destPath), { recursive: true });
2947
+ await fsp.writeFile(destPath, Buffer.from(blobData, "base64"));
2948
+ }
2949
+ const localRev = await this.hashLocalCategories(cfg.categories);
2950
+ const syncState = {
2951
+ version: 1,
2952
+ sha: currentSha,
2953
+ lastSyncedAt: (/* @__PURE__ */ new Date()).toISOString(),
2954
+ localRev
2955
+ };
2956
+ await fsp.writeFile(this.statePath, JSON.stringify(syncState, null, 2), "utf8");
2957
+ this.state = syncState;
2958
+ return {
2959
+ ok: true,
2960
+ action: "pull",
2961
+ categories: cfg.categories,
2962
+ committedAt: currentSha,
2963
+ message: `Pulled ${cfg.categories.join(", ")} from ${cfg.repo}. Commit: ${currentSha.slice(0, 7)}`
2964
+ };
2965
+ }
2966
+ async hasLocalChanges() {
2967
+ if (!this.state) return true;
2968
+ const cfg = this.getConfig();
2969
+ if (!cfg) return true;
2970
+ const current = await this.hashLocalCategories(cfg.categories);
2971
+ return current !== this.state.localRev;
2972
+ }
2973
+ async loadState() {
2974
+ try {
2975
+ const raw = await fsp.readFile(this.statePath, "utf8");
2976
+ this.state = JSON.parse(raw);
2977
+ } catch {
2978
+ this.state = null;
2979
+ }
2980
+ }
2981
+ // ── GitHub API helpers ──────────────────────────────────────────────
2982
+ async githubFetch(token, owner, repo, method, pathSegment, body) {
2983
+ const url = `https://api.github.com/repos/${owner}/${repo}${pathSegment}`;
2984
+ const res = await fetch(url, {
2985
+ method,
2986
+ headers: {
2987
+ Authorization: `Bearer ${token}`,
2988
+ Accept: "application/vnd.github+json",
2989
+ "X-GitHub-Api-Version": "2022-11-28",
2990
+ "Content-Type": "application/json"
2991
+ },
2992
+ body: body !== void 0 ? JSON.stringify(body) : void 0
2993
+ });
2994
+ if (!res.ok) {
2995
+ const errText = await res.text();
2996
+ throw new Error(`GitHub API ${method} ${pathSegment} failed (${res.status}): ${errText}`);
2997
+ }
2998
+ const text = await res.text();
2999
+ return text ? JSON.parse(text) : {};
3000
+ }
3001
+ async getRef(token, owner, repo, ref) {
3002
+ return await this.githubFetch(token, owner, repo, "GET", `/git/refs/heads/${ref}`);
3003
+ }
3004
+ async updateRef(token, owner, repo, ref, sha) {
3005
+ await this.githubFetch(token, owner, repo, "PATCH", `/git/refs/heads/${ref}`, {
3006
+ sha,
3007
+ force: false
3008
+ });
3009
+ }
3010
+ async getCommit(token, owner, repo, sha) {
3011
+ return await this.githubFetch(token, owner, repo, "GET", `/git/commits/${sha}`);
3012
+ }
3013
+ async getTreeEntries(token, owner, repo, treeSha) {
3014
+ return await this.githubFetch(token, owner, repo, "GET", `/git/trees/${treeSha}?recursive=1`);
3015
+ }
3016
+ async createCommit(token, owner, repo, treeSha, parentSha, message = "sync") {
3017
+ const body = { message, tree: treeSha };
3018
+ if (parentSha) body.parents = [parentSha];
3019
+ const result = await this.githubFetch(token, owner, repo, "POST", "/git/commits", body);
3020
+ return result.sha;
3021
+ }
3022
+ async createGitTree(token, owner, repo, entries, baseTreeSha) {
3023
+ const tree = entries.map((e) => ({
3024
+ path: e.path,
3025
+ mode: e.mode,
3026
+ type: "blob",
3027
+ content: e.content
3028
+ }));
3029
+ const body = { tree };
3030
+ if (baseTreeSha) body.base_tree = baseTreeSha;
3031
+ const result = await this.githubFetch(token, owner, repo, "POST", "/git/trees", body);
3032
+ return result.sha;
3033
+ }
3034
+ async getBlob(token, owner, repo, sha) {
3035
+ const result = await this.githubFetch(token, owner, repo, "GET", `/git/blobs/${sha}`);
3036
+ return result.content;
3037
+ }
3038
+ // ── Local file helpers ──────────────────────────────────────────────
3039
+ async buildLocalTree(categories) {
3040
+ const entries = [];
3041
+ const hashes = [];
3042
+ for (const cat of categories) {
3043
+ const localPath = this.categoryToPath(cat);
3044
+ if (!localPath) continue;
3045
+ try {
3046
+ const stat4 = await fsp.stat(localPath);
3047
+ if (stat4.isDirectory()) {
3048
+ const files = await this.walkDir(localPath, localPath);
3049
+ for (const file of files) {
3050
+ const content = await fsp.readFile(file, "utf8");
3051
+ const rel = path7.relative(localPath, file).replace(/\\/g, "/");
3052
+ entries.push({ path: `data/${cat}/${rel}`, content, mode: "100644" });
3053
+ hashes.push(content);
3054
+ }
3055
+ } else {
3056
+ const content = await fsp.readFile(localPath, "utf8");
3057
+ entries.push({ path: `data/${cat}`, content, mode: "100644" });
3058
+ hashes.push(content);
3059
+ }
3060
+ } catch {
3061
+ }
3062
+ }
3063
+ const rev = createHash("sha256").update(hashes.join("")).digest("hex").slice(0, 12);
3064
+ return { treeEntries: entries, rev };
3065
+ }
3066
+ async hashLocalCategories(categories) {
3067
+ const hashes = [];
3068
+ for (const cat of categories) {
3069
+ const localPath = this.categoryToPath(cat);
3070
+ if (!localPath) continue;
3071
+ try {
3072
+ const stat4 = await fsp.stat(localPath);
3073
+ if (stat4.isDirectory()) {
3074
+ const files = await this.walkDir(localPath, localPath);
3075
+ for (const file of files) {
3076
+ const content = await fsp.readFile(file);
3077
+ hashes.push(content.toString("base64") + file);
3078
+ }
3079
+ } else {
3080
+ const content = await fsp.readFile(localPath);
3081
+ hashes.push(content.toString("base64") + localPath);
3082
+ }
3083
+ } catch {
3084
+ }
3085
+ }
3086
+ return createHash("sha256").update(hashes.join("")).digest("hex").slice(0, 12);
3087
+ }
3088
+ categoryToPath(cat) {
3089
+ switch (cat) {
3090
+ case "settings":
3091
+ return this.paths.globalConfig;
3092
+ case "skills":
3093
+ return this.paths.globalSkills;
3094
+ case "prompts":
3095
+ return this.paths.globalPrompts;
3096
+ case "memory":
3097
+ return this.paths.globalMemory;
3098
+ case "history":
3099
+ return this.paths.historyFile;
3100
+ default:
3101
+ return null;
3102
+ }
3103
+ }
3104
+ async walkDir(dir, base) {
3105
+ const results = [];
3106
+ const entries = await fsp.readdir(dir, { withFileTypes: true });
3107
+ for (const entry of entries) {
3108
+ const full = path7.join(dir, entry.name);
3109
+ if (entry.isDirectory()) {
3110
+ results.push(...await this.walkDir(full, base));
3111
+ } else {
3112
+ results.push(full);
3113
+ }
3114
+ }
3115
+ return results;
3116
+ }
3117
+ };
3118
+ function timeAgo(iso) {
3119
+ const diff = Date.now() - new Date(iso).getTime();
3120
+ const mins = Math.floor(diff / 6e4);
3121
+ if (mins < 1) return "just now";
3122
+ if (mins < 60) return `${mins}m ago`;
3123
+ const hrs = Math.floor(mins / 60);
3124
+ if (hrs < 24) return `${hrs}h ago`;
3125
+ const days = Math.floor(hrs / 24);
3126
+ return `${days}d ago`;
3127
+ }
2781
3128
 
2782
- export { ConfigMigrationError, DEFAULT_CONFIG_MIGRATIONS, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultMemoryStore, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DirectorStateCheckpoint, MAX_JOURNAL_ENTRIES, QueueStore, RecoveryLock, SessionAnalyzer, addPlanItem, appendJournal, attachPlanCheckpoint, attachTodosCheckpoint, clearPlan, deriveTodosFromPlanItem, emptyGoal, emptyPlan, formatGoal, formatPlan, formatPlanTemplates, getPlanTemplate, goalFilePath, listPlanTemplates, loadDirectorState, loadGoal, loadPlan, loadTodosCheckpoint, removePlanItem, runConfigMigrations, saveGoal, savePlan, saveTodosCheckpoint, setPlanItemStatus, summarizeUsage };
3129
+ export { ALL_SYNC_CATEGORIES, CloudSync, ConfigMigrationError, DEFAULT_CONFIG_MIGRATIONS, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultMemoryStore, DefaultPromptStore, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DirectorStateCheckpoint, MAX_JOURNAL_ENTRIES, QueueStore, RecoveryLock, SessionAnalyzer, addPlanItem, appendJournal, attachPlanCheckpoint, attachTodosCheckpoint, clearPlan, deriveTodosFromPlanItem, emptyGoal, emptyPlan, formatGoal, formatPlan, formatPlanTemplates, getPlanTemplate, goalFilePath, listPlanTemplates, loadDirectorState, loadGoal, loadPlan, loadTodosCheckpoint, removePlanItem, runConfigMigrations, saveGoal, savePlan, saveTodosCheckpoint, setPlanItemStatus, summarizeUsage };
2783
3130
  //# sourceMappingURL=index.js.map
2784
3131
  //# sourceMappingURL=index.js.map