sanjang 0.3.1 → 0.3.3

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 (69) hide show
  1. package/dashboard/app.js +304 -44
  2. package/dashboard/index.html +43 -6
  3. package/dashboard/style.css +306 -0
  4. package/dist/bin/sanjang.d.ts +1 -0
  5. package/dist/bin/sanjang.js +138 -0
  6. package/dist/lib/config.d.ts +19 -0
  7. package/dist/lib/config.js +318 -0
  8. package/dist/lib/engine/cache.d.ts +7 -0
  9. package/dist/lib/engine/cache.js +183 -0
  10. package/dist/lib/engine/config-hotfix.d.ts +7 -0
  11. package/dist/lib/engine/config-hotfix.js +129 -0
  12. package/dist/lib/engine/conflict.d.ts +12 -0
  13. package/dist/lib/engine/conflict.js +32 -0
  14. package/dist/lib/engine/diagnostics.d.ts +15 -0
  15. package/dist/lib/engine/diagnostics.js +58 -0
  16. package/dist/lib/engine/naming.d.ts +10 -0
  17. package/dist/lib/engine/naming.js +83 -0
  18. package/dist/lib/engine/ports.d.ts +9 -0
  19. package/dist/lib/engine/ports.js +55 -0
  20. package/dist/lib/engine/pr.d.ts +27 -0
  21. package/dist/lib/engine/pr.js +54 -0
  22. package/dist/lib/engine/process.d.ts +15 -0
  23. package/dist/lib/engine/process.js +250 -0
  24. package/dist/lib/engine/self-heal.d.ts +12 -0
  25. package/dist/lib/engine/self-heal.js +98 -0
  26. package/dist/lib/engine/smart-init.d.ts +7 -0
  27. package/dist/lib/engine/smart-init.js +138 -0
  28. package/dist/lib/engine/smart-pr.d.ts +19 -0
  29. package/dist/lib/engine/smart-pr.js +105 -0
  30. package/dist/lib/engine/snapshot.d.ts +10 -0
  31. package/dist/lib/engine/snapshot.js +35 -0
  32. package/dist/lib/engine/state.d.ts +7 -0
  33. package/dist/lib/engine/state.js +53 -0
  34. package/dist/lib/engine/suggest.d.ts +21 -0
  35. package/dist/lib/engine/suggest.js +121 -0
  36. package/dist/lib/engine/warp.d.ts +23 -0
  37. package/dist/lib/engine/warp.js +32 -0
  38. package/dist/lib/engine/watcher.d.ts +11 -0
  39. package/dist/lib/engine/watcher.js +43 -0
  40. package/dist/lib/engine/worktree.d.ts +13 -0
  41. package/dist/lib/engine/worktree.js +91 -0
  42. package/dist/lib/server.d.ts +20 -0
  43. package/dist/lib/server.js +1466 -0
  44. package/dist/lib/types.d.ts +109 -0
  45. package/dist/lib/types.js +2 -0
  46. package/package.json +5 -4
  47. package/bin/__tests__/sanjang.test.ts +0 -42
  48. package/bin/sanjang.js +0 -17
  49. package/bin/sanjang.ts +0 -144
  50. package/lib/config.ts +0 -337
  51. package/lib/engine/cache.ts +0 -218
  52. package/lib/engine/config-hotfix.ts +0 -161
  53. package/lib/engine/conflict.ts +0 -33
  54. package/lib/engine/diagnostics.ts +0 -81
  55. package/lib/engine/naming.ts +0 -93
  56. package/lib/engine/ports.ts +0 -61
  57. package/lib/engine/pr.ts +0 -71
  58. package/lib/engine/process.ts +0 -283
  59. package/lib/engine/self-heal.ts +0 -130
  60. package/lib/engine/smart-init.ts +0 -136
  61. package/lib/engine/smart-pr.ts +0 -130
  62. package/lib/engine/snapshot.ts +0 -45
  63. package/lib/engine/state.ts +0 -60
  64. package/lib/engine/suggest.ts +0 -169
  65. package/lib/engine/warp.ts +0 -47
  66. package/lib/engine/watcher.ts +0 -40
  67. package/lib/engine/worktree.ts +0 -100
  68. package/lib/server.ts +0 -1560
  69. package/lib/types.ts +0 -130
@@ -0,0 +1,11 @@
1
+ export declare class CampWatcher {
2
+ private readonly dir;
3
+ private readonly onChange;
4
+ private readonly debounceMs;
5
+ private watcher;
6
+ private timer;
7
+ private stopped;
8
+ constructor(dir: string, onChange: () => void, debounceMs?: number);
9
+ start(): void;
10
+ stop(): void;
11
+ }
@@ -0,0 +1,43 @@
1
+ import { watch } from "node:fs";
2
+ export class CampWatcher {
3
+ dir;
4
+ onChange;
5
+ debounceMs;
6
+ watcher = null;
7
+ timer = null;
8
+ stopped = false;
9
+ constructor(dir, onChange, debounceMs = 500) {
10
+ this.dir = dir;
11
+ this.onChange = onChange;
12
+ this.debounceMs = debounceMs;
13
+ }
14
+ start() {
15
+ this.stopped = false;
16
+ try {
17
+ this.watcher = watch(this.dir, { recursive: true }, () => {
18
+ if (this.stopped)
19
+ return;
20
+ if (this.timer)
21
+ clearTimeout(this.timer);
22
+ this.timer = setTimeout(() => {
23
+ if (!this.stopped)
24
+ this.onChange();
25
+ }, this.debounceMs);
26
+ });
27
+ }
28
+ catch {
29
+ // fs.watch can fail on some platforms/dirs — silently degrade
30
+ }
31
+ }
32
+ stop() {
33
+ this.stopped = true;
34
+ if (this.timer) {
35
+ clearTimeout(this.timer);
36
+ this.timer = null;
37
+ }
38
+ if (this.watcher) {
39
+ this.watcher.close();
40
+ this.watcher = null;
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,13 @@
1
+ export interface BranchInfo {
2
+ name: string;
3
+ remote: boolean;
4
+ local: boolean;
5
+ date: string;
6
+ category?: "default" | "feature" | "fix" | "other";
7
+ }
8
+ export declare function setProjectRoot(root: string): void;
9
+ export declare function getProjectRoot(): string;
10
+ export declare function campPath(name: string): string;
11
+ export declare function listBranches(): Promise<BranchInfo[]>;
12
+ export declare function addWorktree(name: string, branch: string): Promise<void>;
13
+ export declare function removeWorktree(name: string): Promise<void>;
@@ -0,0 +1,91 @@
1
+ import { join } from "node:path";
2
+ import { simpleGit } from "simple-git";
3
+ import { getCampsDir } from "./state.js";
4
+ let projectRoot = null;
5
+ export function setProjectRoot(root) {
6
+ projectRoot = root;
7
+ }
8
+ export function getProjectRoot() {
9
+ if (!projectRoot)
10
+ throw new Error("projectRoot not initialized. Call setProjectRoot() first.");
11
+ return projectRoot;
12
+ }
13
+ export function campPath(name) {
14
+ return join(getCampsDir(), name);
15
+ }
16
+ function git() {
17
+ return simpleGit(getProjectRoot());
18
+ }
19
+ export async function listBranches() {
20
+ // Best-effort fetch — continue with local refs on network failure
21
+ try {
22
+ await git().fetch(["--prune"]);
23
+ }
24
+ catch {
25
+ /* offline is OK */
26
+ }
27
+ const raw = await git().raw([
28
+ "for-each-ref",
29
+ "--sort=-committerdate",
30
+ "--format=%(refname:short)\t%(committerdate:relative)\t%(refname)",
31
+ "refs/heads/",
32
+ "refs/remotes/origin/",
33
+ ]);
34
+ const map = new Map();
35
+ for (const line of raw.trim().split("\n")) {
36
+ if (!line)
37
+ continue;
38
+ const [shortName, date, fullRef] = line.split("\t");
39
+ if (!shortName || !fullRef)
40
+ continue;
41
+ if (shortName.includes("HEAD"))
42
+ continue;
43
+ const isRemote = fullRef.startsWith("refs/remotes/origin/");
44
+ const clean = shortName.replace(/^origin\//, "").trim();
45
+ if (!clean)
46
+ continue;
47
+ const entry = map.get(clean) || { name: clean, remote: false, local: false, date: date ?? "" };
48
+ if (isRemote)
49
+ entry.remote = true;
50
+ else
51
+ entry.local = true;
52
+ if (!entry.date)
53
+ entry.date = date ?? "";
54
+ map.set(clean, entry);
55
+ }
56
+ const branches = [...map.values()];
57
+ for (const b of branches) {
58
+ if (["dev", "main", "master"].includes(b.name)) {
59
+ b.category = "default";
60
+ }
61
+ else if (b.name.startsWith("feature/")) {
62
+ b.category = "feature";
63
+ }
64
+ else if (b.name.startsWith("fix/") || b.name.startsWith("hotfix/")) {
65
+ b.category = "fix";
66
+ }
67
+ else {
68
+ b.category = "other";
69
+ }
70
+ }
71
+ return branches;
72
+ }
73
+ export async function addWorktree(name, branch) {
74
+ const path = campPath(name);
75
+ const refs = [`origin/${branch}`, branch];
76
+ let lastErr;
77
+ for (const ref of refs) {
78
+ try {
79
+ await git().raw(["worktree", "add", "--detach", path, ref]);
80
+ return;
81
+ }
82
+ catch (err) {
83
+ lastErr = err;
84
+ }
85
+ }
86
+ throw lastErr;
87
+ }
88
+ export async function removeWorktree(name) {
89
+ const path = campPath(name);
90
+ await git().raw(["worktree", "remove", "--force", path]);
91
+ }
@@ -0,0 +1,20 @@
1
+ import { type ChildProcess } from "node:child_process";
2
+ import { type Server } from "node:http";
3
+ import express from "express";
4
+ import { CampWatcher } from "./engine/watcher.ts";
5
+ interface CreateAppOptions {
6
+ port?: number;
7
+ }
8
+ interface CreateAppResult {
9
+ app: express.Application;
10
+ server: Server;
11
+ port: number;
12
+ runningTasks: Map<string, ChildProcess>;
13
+ warpStatus: {
14
+ installed: boolean;
15
+ };
16
+ watchers: Map<string, CampWatcher>;
17
+ }
18
+ export declare function createApp(projectRoot: string, options?: CreateAppOptions): Promise<CreateAppResult>;
19
+ export declare function startServer(projectRoot: string, options?: CreateAppOptions): Promise<Server>;
20
+ export {};