agentsx 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 (86) hide show
  1. package/AGENTS.md +49 -0
  2. package/AGENT_PATHS.md +55 -0
  3. package/README.md +32 -0
  4. package/REQUIREMENTS.md +133 -0
  5. package/dist/agents/claude.d.ts +2 -0
  6. package/dist/agents/claude.js +120 -0
  7. package/dist/agents/claude.js.map +1 -0
  8. package/dist/agents/codex.d.ts +2 -0
  9. package/dist/agents/codex.js +68 -0
  10. package/dist/agents/codex.js.map +1 -0
  11. package/dist/agents/copilot.d.ts +2 -0
  12. package/dist/agents/copilot.js +85 -0
  13. package/dist/agents/copilot.js.map +1 -0
  14. package/dist/agents/cursor.d.ts +2 -0
  15. package/dist/agents/cursor.js +84 -0
  16. package/dist/agents/cursor.js.map +1 -0
  17. package/dist/agents/opencode.d.ts +2 -0
  18. package/dist/agents/opencode.js +90 -0
  19. package/dist/agents/opencode.js.map +1 -0
  20. package/dist/agents/registry.d.ts +4 -0
  21. package/dist/agents/registry.js +35 -0
  22. package/dist/agents/registry.js.map +1 -0
  23. package/dist/commands/init.d.ts +1 -0
  24. package/dist/commands/init.js +15 -0
  25. package/dist/commands/init.js.map +1 -0
  26. package/dist/commands/pull.d.ts +2 -0
  27. package/dist/commands/pull.js +5 -0
  28. package/dist/commands/pull.js.map +1 -0
  29. package/dist/commands/push.d.ts +2 -0
  30. package/dist/commands/push.js +5 -0
  31. package/dist/commands/push.js.map +1 -0
  32. package/dist/commands/sync.d.ts +2 -0
  33. package/dist/commands/sync.js +5 -0
  34. package/dist/commands/sync.js.map +1 -0
  35. package/dist/commands/targets.d.ts +1 -0
  36. package/dist/commands/targets.js +17 -0
  37. package/dist/commands/targets.js.map +1 -0
  38. package/dist/core/git.d.ts +6 -0
  39. package/dist/core/git.js +45 -0
  40. package/dist/core/git.js.map +1 -0
  41. package/dist/core/layout.d.ts +3 -0
  42. package/dist/core/layout.js +9 -0
  43. package/dist/core/layout.js.map +1 -0
  44. package/dist/core/planner.d.ts +3 -0
  45. package/dist/core/planner.js +173 -0
  46. package/dist/core/planner.js.map +1 -0
  47. package/dist/core/remote.d.ts +9 -0
  48. package/dist/core/remote.js +28 -0
  49. package/dist/core/remote.js.map +1 -0
  50. package/dist/core/run-sync-command.d.ts +2 -0
  51. package/dist/core/run-sync-command.js +53 -0
  52. package/dist/core/run-sync-command.js.map +1 -0
  53. package/dist/core/scanner.d.ts +4 -0
  54. package/dist/core/scanner.js +58 -0
  55. package/dist/core/scanner.js.map +1 -0
  56. package/dist/core/state.d.ts +10 -0
  57. package/dist/core/state.js +64 -0
  58. package/dist/core/state.js.map +1 -0
  59. package/dist/core/sync-engine.d.ts +21 -0
  60. package/dist/core/sync-engine.js +133 -0
  61. package/dist/core/sync-engine.js.map +1 -0
  62. package/dist/core/targets.d.ts +6 -0
  63. package/dist/core/targets.js +28 -0
  64. package/dist/core/targets.js.map +1 -0
  65. package/dist/index.d.ts +2 -0
  66. package/dist/index.js +86 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/types.d.ts +79 -0
  69. package/dist/types.js +2 -0
  70. package/dist/types.js.map +1 -0
  71. package/dist/ui/prompts.d.ts +4 -0
  72. package/dist/ui/prompts.js +56 -0
  73. package/dist/ui/prompts.js.map +1 -0
  74. package/dist/utils/fs.d.ts +14 -0
  75. package/dist/utils/fs.js +63 -0
  76. package/dist/utils/fs.js.map +1 -0
  77. package/dist/utils/hash.d.ts +1 -0
  78. package/dist/utils/hash.js +7 -0
  79. package/dist/utils/hash.js.map +1 -0
  80. package/dist/utils/path.d.ts +5 -0
  81. package/dist/utils/path.js +46 -0
  82. package/dist/utils/path.js.map +1 -0
  83. package/dist/utils/shell.d.ts +7 -0
  84. package/dist/utils/shell.js +32 -0
  85. package/dist/utils/shell.js.map +1 -0
  86. package/package.json +45 -0
@@ -0,0 +1,58 @@
1
+ import path from "node:path";
2
+ import { exists, listFilesRecursive, statFile } from "../utils/fs.js";
3
+ import { hashFile } from "../utils/hash.js";
4
+ import { getLocalTargetBase, getRemoteTargetBase } from "./layout.js";
5
+ async function toSnapshot(absPath, mtimeMs) {
6
+ return {
7
+ absPath,
8
+ hash: await hashFile(absPath),
9
+ mtimeMs,
10
+ };
11
+ }
12
+ export async function scanTargetSide(basePath, target, targetId) {
13
+ if (!(await exists(basePath))) {
14
+ return [];
15
+ }
16
+ if (target.kind === "file") {
17
+ const fileStat = await statFile(basePath);
18
+ if (!fileStat) {
19
+ return [];
20
+ }
21
+ return [
22
+ {
23
+ targetId,
24
+ relPath: path.basename(basePath),
25
+ snapshot: await toSnapshot(basePath, fileStat.mtimeMs),
26
+ },
27
+ ];
28
+ }
29
+ const files = await listFilesRecursive(basePath);
30
+ const entries = [];
31
+ for (const file of files) {
32
+ entries.push({
33
+ targetId,
34
+ relPath: file.relPath,
35
+ snapshot: await toSnapshot(file.absPath, file.mtimeMs),
36
+ });
37
+ }
38
+ return entries;
39
+ }
40
+ export async function scanLocalEntries(cwd, targets) {
41
+ const all = [];
42
+ for (const target of targets) {
43
+ const basePath = getLocalTargetBase(target, cwd);
44
+ const entries = await scanTargetSide(basePath, target, target.id);
45
+ all.push(...entries);
46
+ }
47
+ return all;
48
+ }
49
+ export async function scanRemoteEntries(mirrorPath, agent, targets) {
50
+ const all = [];
51
+ for (const target of targets) {
52
+ const basePath = getRemoteTargetBase(mirrorPath, agent, target);
53
+ const entries = await scanTargetSide(basePath, target, target.id);
54
+ all.push(...entries);
55
+ }
56
+ return all;
57
+ }
58
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/core/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEtE,KAAK,UAAU,UAAU,CAAC,OAAe,EAAE,OAAe;IACxD,OAAO;QACL,OAAO;QACP,IAAI,EAAE,MAAM,QAAQ,CAAC,OAAO,CAAC;QAC7B,OAAO;KACR,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAgB,EAChB,MAAkB,EAClB,QAAgB;IAEhB,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;QAC9B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,OAAO;YACL;gBACE,QAAQ;gBACR,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBAChC,QAAQ,EAAE,MAAM,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC;aACvD;SACF,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACjD,MAAM,OAAO,GAAgB,EAAE,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC;YACX,QAAQ;YACR,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,QAAQ,EAAE,MAAM,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC;SACvD,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAW,EACX,OAAqB;IAErB,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAClE,GAAG,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,UAAkB,EAClB,KAAmB,EACnB,OAAqB;IAErB,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,mBAAmB,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAClE,GAAG,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { AgentsxState, ConflictPolicy, PerFileDecision } from "../types.js";
2
+ export declare function getStateDir(): string;
3
+ export declare function getStateFile(): string;
4
+ export declare function createDefaultState(): AgentsxState;
5
+ export declare function loadState(): Promise<AgentsxState>;
6
+ export declare function saveState(state: AgentsxState): Promise<void>;
7
+ export declare function conflictDefaultKey(command: string, agent: string, targetIds: string[]): string;
8
+ export declare function rememberConflictDefault(state: AgentsxState, key: string, policy: ConflictPolicy): void;
9
+ export declare function rememberConflictDecision(state: AgentsxState, key: string, relKey: string, decision: PerFileDecision): void;
10
+ export declare function getRememberedDecision(state: AgentsxState, key: string, relKey: string): PerFileDecision | undefined;
@@ -0,0 +1,64 @@
1
+ import { homedir } from "node:os";
2
+ import path from "node:path";
3
+ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
4
+ const STATE_DIR = path.join(homedir(), ".agentsx");
5
+ const STATE_FILE = path.join(STATE_DIR, "state.json");
6
+ const SCHEMA_VERSION = 1;
7
+ export function getStateDir() {
8
+ return STATE_DIR;
9
+ }
10
+ export function getStateFile() {
11
+ return STATE_FILE;
12
+ }
13
+ export function createDefaultState() {
14
+ return {
15
+ schemaVersion: SCHEMA_VERSION,
16
+ remote: undefined,
17
+ lastSyncAtByAgent: {},
18
+ conflictDefaults: {},
19
+ conflictChoices: {},
20
+ };
21
+ }
22
+ export async function loadState() {
23
+ await mkdir(STATE_DIR, { recursive: true });
24
+ try {
25
+ const raw = await readFile(STATE_FILE, "utf8");
26
+ const parsed = JSON.parse(raw);
27
+ return {
28
+ schemaVersion: SCHEMA_VERSION,
29
+ remote: parsed.remote,
30
+ lastSyncAtByAgent: parsed.lastSyncAtByAgent ?? {},
31
+ conflictDefaults: parsed.conflictDefaults ?? {},
32
+ conflictChoices: parsed.conflictChoices ?? {},
33
+ };
34
+ }
35
+ catch (error) {
36
+ if (error.code === "ENOENT") {
37
+ const defaultState = createDefaultState();
38
+ await saveState(defaultState);
39
+ return defaultState;
40
+ }
41
+ throw new Error(`상태 파일을 읽을 수 없습니다. 파일: ${STATE_FILE}. 파일이 손상되었을 수 있습니다.`);
42
+ }
43
+ }
44
+ export async function saveState(state) {
45
+ await mkdir(STATE_DIR, { recursive: true });
46
+ const tmpFile = `${STATE_FILE}.tmp`;
47
+ await writeFile(tmpFile, JSON.stringify(state, null, 2), "utf8");
48
+ await rename(tmpFile, STATE_FILE);
49
+ }
50
+ export function conflictDefaultKey(command, agent, targetIds) {
51
+ return `${command}:${agent}:${targetIds.slice().sort().join(",")}`;
52
+ }
53
+ export function rememberConflictDefault(state, key, policy) {
54
+ state.conflictDefaults[key] = policy;
55
+ }
56
+ export function rememberConflictDecision(state, key, relKey, decision) {
57
+ const existing = state.conflictChoices[key] ?? {};
58
+ existing[relKey] = decision;
59
+ state.conflictChoices[key] = existing;
60
+ }
61
+ export function getRememberedDecision(state, key, relKey) {
62
+ return state.conflictChoices[key]?.[relKey];
63
+ }
64
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/core/state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { AgentAdapter, AgentsxState, ConflictPolicy, SyncCommand, TargetSpec } from "../types.js";
2
+ interface SyncEngineOptions {
3
+ command: SyncCommand;
4
+ adapter: AgentAdapter;
5
+ targets: TargetSpec[];
6
+ cwd: string;
7
+ mirrorPath: string;
8
+ state: AgentsxState;
9
+ conflictStateKey: string;
10
+ interactiveTargets: boolean;
11
+ explicitPolicy: ConflictPolicy | undefined;
12
+ }
13
+ interface ExecutionSummary {
14
+ copiedLocalToRemote: number;
15
+ copiedRemoteToLocal: number;
16
+ skipped: number;
17
+ conflicts: number;
18
+ policy: ConflictPolicy | undefined;
19
+ }
20
+ export declare function executeSyncEngine(options: SyncEngineOptions): Promise<ExecutionSummary>;
21
+ export {};
@@ -0,0 +1,133 @@
1
+ import path from "node:path";
2
+ import { copySingleFile } from "../utils/fs.js";
3
+ import { getRememberedDecision, rememberConflictDecision, rememberConflictDefault } from "./state.js";
4
+ import { getLocalTargetBase, getRemoteTargetBase } from "./layout.js";
5
+ import { buildPlan, mergeEntries } from "./planner.js";
6
+ import { scanLocalEntries, scanRemoteEntries } from "./scanner.js";
7
+ import { promptConflictPolicy, promptPerFileDecision } from "../ui/prompts.js";
8
+ function opToDecision(command, decision) {
9
+ if (decision === "skip") {
10
+ return "skip";
11
+ }
12
+ if (decision === "use-source") {
13
+ return command === "pull" ? "copy-remote-to-local" : "copy-local-to-remote";
14
+ }
15
+ if (decision === "use-local") {
16
+ return "copy-local-to-remote";
17
+ }
18
+ if (decision === "use-remote") {
19
+ return "copy-remote-to-local";
20
+ }
21
+ return "skip";
22
+ }
23
+ function resolvePathForTarget(base, target, relPath) {
24
+ if (target.kind === "file") {
25
+ return base;
26
+ }
27
+ return path.join(base, relPath);
28
+ }
29
+ function createTargetMap(targets) {
30
+ const map = new Map();
31
+ for (const target of targets) {
32
+ map.set(target.id, target);
33
+ }
34
+ return map;
35
+ }
36
+ export async function executeSyncEngine(options) {
37
+ const localEntries = await scanLocalEntries(options.cwd, options.targets);
38
+ const remoteEntries = await scanRemoteEntries(options.mirrorPath, options.adapter, options.targets);
39
+ const localByKey = new Map(localEntries.map((item) => [`${item.targetId}:${item.relPath}`, item.snapshot]));
40
+ const remoteByKey = new Map(remoteEntries.map((item) => [`${item.targetId}:${item.relPath}`, item.snapshot]));
41
+ const targetById = createTargetMap(options.targets);
42
+ const merged = mergeEntries(localEntries, remoteEntries);
43
+ let selectedPolicy;
44
+ let ops = [];
45
+ let conflicts = 0;
46
+ if (!options.interactiveTargets) {
47
+ selectedPolicy =
48
+ options.explicitPolicy ??
49
+ options.state.conflictDefaults[options.conflictStateKey] ??
50
+ (await promptConflictPolicy(options.state.conflictDefaults[options.conflictStateKey]));
51
+ rememberConflictDefault(options.state, options.conflictStateKey, selectedPolicy);
52
+ const planned = buildPlan(merged, options.command, selectedPolicy);
53
+ conflicts = planned.conflicts.length;
54
+ if (planned.blocked) {
55
+ const names = planned.conflicts.map((item) => item.relPath).join(", ");
56
+ throw new Error(`충돌로 인해 전체 실패했습니다. 정책: fail-all. 충돌 파일: ${names}`);
57
+ }
58
+ ops = planned.ops;
59
+ }
60
+ else {
61
+ const planned = buildPlan(merged, options.command, "partial");
62
+ conflicts = planned.conflicts.length;
63
+ const filtered = planned.ops.filter((op) => op.reason !== "conflict-skip");
64
+ ops = [...filtered];
65
+ for (const conflict of planned.conflicts) {
66
+ const remembered = getRememberedDecision(options.state, options.conflictStateKey, conflict.key);
67
+ const decision = remembered ?? (await promptPerFileDecision(options.command, conflict));
68
+ rememberConflictDecision(options.state, options.conflictStateKey, conflict.key, decision);
69
+ const action = opToDecision(options.command, decision);
70
+ if (action === "skip") {
71
+ ops.push({
72
+ key: conflict.key,
73
+ targetId: conflict.targetId,
74
+ relPath: conflict.relPath,
75
+ action: "skip",
76
+ reason: "conflict-skip",
77
+ });
78
+ }
79
+ else {
80
+ ops.push({
81
+ key: conflict.key,
82
+ targetId: conflict.targetId,
83
+ relPath: conflict.relPath,
84
+ action,
85
+ reason: "overwrite",
86
+ });
87
+ }
88
+ }
89
+ }
90
+ let copiedLocalToRemote = 0;
91
+ let copiedRemoteToLocal = 0;
92
+ let skipped = 0;
93
+ for (const op of ops) {
94
+ const target = targetById.get(op.targetId);
95
+ if (!target) {
96
+ skipped += 1;
97
+ continue;
98
+ }
99
+ const localBase = getLocalTargetBase(target, options.cwd);
100
+ const remoteBase = getRemoteTargetBase(options.mirrorPath, options.adapter, target);
101
+ const localDest = resolvePathForTarget(localBase, target, op.relPath);
102
+ const remoteDest = resolvePathForTarget(remoteBase, target, op.relPath);
103
+ if (op.action === "copy-local-to-remote") {
104
+ const source = localByKey.get(op.key)?.absPath;
105
+ if (!source) {
106
+ skipped += 1;
107
+ continue;
108
+ }
109
+ await copySingleFile(source, remoteDest);
110
+ copiedLocalToRemote += 1;
111
+ continue;
112
+ }
113
+ if (op.action === "copy-remote-to-local") {
114
+ const source = remoteByKey.get(op.key)?.absPath;
115
+ if (!source) {
116
+ skipped += 1;
117
+ continue;
118
+ }
119
+ await copySingleFile(source, localDest);
120
+ copiedRemoteToLocal += 1;
121
+ continue;
122
+ }
123
+ skipped += 1;
124
+ }
125
+ return {
126
+ copiedLocalToRemote,
127
+ copiedRemoteToLocal,
128
+ skipped,
129
+ conflicts,
130
+ policy: selectedPolicy,
131
+ };
132
+ }
133
+ //# sourceMappingURL=sync-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-engine.js","sourceRoot":"","sources":["../../src/core/sync-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { AgentAdapter, TargetSpec } from "../types.js";
2
+ export interface TargetSelection {
3
+ targets: TargetSpec[];
4
+ interactive: boolean;
5
+ }
6
+ export declare function selectTargets(adapter: AgentAdapter, requestedTargetIds: string[]): Promise<TargetSelection>;
@@ -0,0 +1,28 @@
1
+ import { promptSelectTargets } from "../ui/prompts.js";
2
+ export async function selectTargets(adapter, requestedTargetIds) {
3
+ const requested = requestedTargetIds.map((item) => item.trim()).filter(Boolean);
4
+ if (requested.length === 0) {
5
+ const selectedIds = await promptSelectTargets(adapter, adapter.targets);
6
+ const selectedTargets = adapter.targets.filter((target) => selectedIds.includes(target.id));
7
+ return {
8
+ targets: selectedTargets,
9
+ interactive: true,
10
+ };
11
+ }
12
+ const byId = new Map(adapter.targets.map((target) => [target.id, target]));
13
+ const selectedTargets = [];
14
+ for (const targetId of requested) {
15
+ const target = byId.get(targetId);
16
+ if (!target) {
17
+ throw new Error(`대상 '${targetId}'를 찾을 수 없습니다. 사용 가능한 대상: ${adapter.targets
18
+ .map((item) => item.id)
19
+ .join(", ")}`);
20
+ }
21
+ selectedTargets.push(target);
22
+ }
23
+ return {
24
+ targets: selectedTargets,
25
+ interactive: false,
26
+ };
27
+ }
28
+ //# sourceMappingURL=targets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targets.js","sourceRoot":"","sources":["../../src/core/targets.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAOvD,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAAqB,EACrB,kBAA4B;IAE5B,MAAM,SAAS,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEhF,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,WAAW,GAAG,MAAM,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QACxE,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5F,OAAO;YACL,OAAO,EAAE,eAAe;YACxB,WAAW,EAAE,IAAI;SAClB,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAC3E,MAAM,eAAe,GAAiB,EAAE,CAAC;IACzC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,OAAO,QAAQ,4BAA4B,OAAO,CAAC,OAAO;iBACvD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;iBACtB,IAAI,CAAC,IAAI,CAAC,EAAE,CAChB,CAAC;QACJ,CAAC;QACD,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO;QACL,OAAO,EAAE,eAAe;QACxB,WAAW,EAAE,KAAK;KACnB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+ import { or, object } from "@optique/core/constructs";
3
+ import { command, constant, argument, option } from "@optique/core/primitives";
4
+ import { multiple, optional } from "@optique/core/modifiers";
5
+ import { choice, string } from "@optique/core/valueparser";
6
+ import { run } from "@optique/run";
7
+ import { runInit } from "./commands/init.js";
8
+ import { runPull } from "./commands/pull.js";
9
+ import { runPush } from "./commands/push.js";
10
+ import { runSync } from "./commands/sync.js";
11
+ import { runTargets } from "./commands/targets.js";
12
+ import { listSupportedAgents } from "./agents/registry.js";
13
+ const conflictPolicyParser = choice(["fail-all", "overwrite", "partial"], { metavar: "POLICY" });
14
+ const initCommand = command("init", object({
15
+ action: constant("init"),
16
+ repoUrl: argument(string({ metavar: "REPO_URL" })),
17
+ }));
18
+ const agentsCommand = command("agents", object({
19
+ action: constant("agents"),
20
+ }));
21
+ const targetsCommand = command("targets", object({
22
+ action: constant("targets"),
23
+ agent: argument(string({ metavar: "AGENT" })),
24
+ }));
25
+ const pushCommand = command("push", object({
26
+ action: constant("push"),
27
+ agent: argument(string({ metavar: "AGENT" })),
28
+ targets: multiple(argument(string({ metavar: "TARGET" }))),
29
+ conflict: optional(option("--conflict", conflictPolicyParser)),
30
+ }));
31
+ const pullCommand = command("pull", object({
32
+ action: constant("pull"),
33
+ agent: argument(string({ metavar: "AGENT" })),
34
+ targets: multiple(argument(string({ metavar: "TARGET" }))),
35
+ conflict: optional(option("--conflict", conflictPolicyParser)),
36
+ }));
37
+ const syncCommand = command("sync", object({
38
+ action: constant("sync"),
39
+ agent: argument(string({ metavar: "AGENT" })),
40
+ targets: multiple(argument(string({ metavar: "TARGET" }))),
41
+ conflict: optional(option("--conflict", conflictPolicyParser)),
42
+ }));
43
+ const parser = or(initCommand, agentsCommand, targetsCommand, pushCommand, pullCommand, syncCommand);
44
+ async function main() {
45
+ try {
46
+ const result = run(parser, {
47
+ programName: "agentsx",
48
+ help: "both",
49
+ version: {
50
+ value: "0.1.0",
51
+ mode: "option",
52
+ },
53
+ });
54
+ if (result.action === "init") {
55
+ await runInit(result.repoUrl);
56
+ return;
57
+ }
58
+ if (result.action === "agents") {
59
+ const lines = listSupportedAgents().map((agent) => `${agent.key} (${agent.displayName})\n - ${agent.references.join("\n - ")}`);
60
+ console.log(lines.join("\n"));
61
+ return;
62
+ }
63
+ if (result.action === "targets") {
64
+ runTargets(result.agent);
65
+ return;
66
+ }
67
+ if (result.action === "push") {
68
+ await runPush(result.agent, [...result.targets], result.conflict);
69
+ return;
70
+ }
71
+ if (result.action === "pull") {
72
+ await runPull(result.agent, [...result.targets], result.conflict);
73
+ return;
74
+ }
75
+ if (result.action === "sync") {
76
+ await runSync(result.agent, [...result.targets], result.conflict);
77
+ }
78
+ }
79
+ catch (error) {
80
+ const message = error instanceof Error ? error.message : "알 수 없는 오류";
81
+ console.error(`오류: ${message}`);
82
+ process.exitCode = 1;
83
+ }
84
+ }
85
+ await main();
86
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ export type AgentKey = "codex" | "claude" | "cursor" | "opencode" | "copilot";
2
+ export type SyncCommand = "push" | "pull" | "sync";
3
+ export type ConflictPolicy = "fail-all" | "overwrite" | "partial";
4
+ export type PerFileDecision = "use-source" | "use-local" | "use-remote" | "skip";
5
+ export type TargetKind = "file" | "dir";
6
+ export type TargetScope = "home" | "cwd";
7
+ export type PlatformPath = string | {
8
+ darwin?: string;
9
+ linux?: string;
10
+ win32?: string;
11
+ default?: string;
12
+ };
13
+ export interface TargetSpec {
14
+ id: string;
15
+ label: string;
16
+ description: string;
17
+ category: "skills" | "plugins" | "mcp" | "instructions" | "config" | "other";
18
+ kind: TargetKind;
19
+ scope: TargetScope;
20
+ path: PlatformPath;
21
+ optional?: boolean;
22
+ sensitive?: boolean;
23
+ includeByDefault?: boolean;
24
+ }
25
+ export interface AgentAdapter {
26
+ key: AgentKey;
27
+ displayName: string;
28
+ aliases: string[];
29
+ references: string[];
30
+ targets: TargetSpec[];
31
+ }
32
+ export interface RemoteConfig {
33
+ repoUrl: string;
34
+ mirrorPath: string;
35
+ defaultBranch: string;
36
+ }
37
+ export interface AgentsxState {
38
+ schemaVersion: number;
39
+ remote: RemoteConfig | undefined;
40
+ lastSyncAtByAgent: Partial<Record<AgentKey, string>>;
41
+ conflictDefaults: Record<string, ConflictPolicy>;
42
+ conflictChoices: Record<string, Record<string, PerFileDecision>>;
43
+ }
44
+ export interface FileSnapshot {
45
+ absPath: string;
46
+ hash: string;
47
+ mtimeMs: number;
48
+ }
49
+ export interface SideEntry {
50
+ targetId: string;
51
+ relPath: string;
52
+ snapshot: FileSnapshot;
53
+ }
54
+ export interface SyncEntry {
55
+ key: string;
56
+ targetId: string;
57
+ relPath: string;
58
+ local: FileSnapshot | undefined;
59
+ remote: FileSnapshot | undefined;
60
+ }
61
+ export interface PlannedOp {
62
+ key: string;
63
+ targetId: string;
64
+ relPath: string;
65
+ action: "copy-local-to-remote" | "copy-remote-to-local" | "skip";
66
+ reason: "new" | "overwrite" | "same" | "conflict-skip";
67
+ }
68
+ export interface ConflictItem {
69
+ key: string;
70
+ targetId: string;
71
+ relPath: string;
72
+ local: FileSnapshot | undefined;
73
+ remote: FileSnapshot | undefined;
74
+ }
75
+ export interface PlanResult {
76
+ ops: PlannedOp[];
77
+ conflicts: ConflictItem[];
78
+ blocked: boolean;
79
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ import type { AgentAdapter, ConflictItem, ConflictPolicy, PerFileDecision, SyncCommand, TargetSpec } from "../types.js";
2
+ export declare function promptSelectTargets(adapter: AgentAdapter, targets: TargetSpec[]): Promise<string[]>;
3
+ export declare function promptConflictPolicy(defaultPolicy?: ConflictPolicy): Promise<ConflictPolicy>;
4
+ export declare function promptPerFileDecision(command: SyncCommand, conflict: ConflictItem): Promise<PerFileDecision>;
@@ -0,0 +1,56 @@
1
+ import { checkbox, select } from "@inquirer/prompts";
2
+ export async function promptSelectTargets(adapter, targets) {
3
+ const selected = await checkbox({
4
+ message: `${adapter.displayName} 동기화 대상을 선택하세요. (↑/↓ 이동, Space 선택, Enter 확정)`,
5
+ choices: targets.map((target) => ({
6
+ name: `${target.id} - ${target.description}${target.sensitive ? " [민감]" : ""}`,
7
+ value: target.id,
8
+ checked: target.includeByDefault ?? !target.sensitive,
9
+ })),
10
+ required: true,
11
+ });
12
+ return selected;
13
+ }
14
+ export async function promptConflictPolicy(defaultPolicy) {
15
+ const result = await select({
16
+ message: "충돌 처리 방식을 선택하세요.",
17
+ default: defaultPolicy,
18
+ choices: [
19
+ {
20
+ value: "fail-all",
21
+ name: "fail-all (충돌이 하나라도 있으면 전체 실패)",
22
+ },
23
+ {
24
+ value: "overwrite",
25
+ name: "overwrite (현재 명령 기준으로 덮어쓰기)",
26
+ },
27
+ {
28
+ value: "partial",
29
+ name: "partial (충돌은 건너뛰고 나머지만 진행)",
30
+ },
31
+ ],
32
+ });
33
+ return result;
34
+ }
35
+ export async function promptPerFileDecision(command, conflict) {
36
+ if (command === "push" || command === "pull") {
37
+ const result = await select({
38
+ message: `충돌: ${conflict.relPath}`,
39
+ choices: [
40
+ { value: "use-source", name: "덮어쓰기" },
41
+ { value: "skip", name: "건너뛰기" },
42
+ ],
43
+ });
44
+ return result;
45
+ }
46
+ const result = await select({
47
+ message: `충돌: ${conflict.relPath}`,
48
+ choices: [
49
+ { value: "use-local", name: "로컬 버전 사용" },
50
+ { value: "use-remote", name: "원격 버전 사용" },
51
+ { value: "skip", name: "건너뛰기" },
52
+ ],
53
+ });
54
+ return result;
55
+ }
56
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/ui/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAUrD,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAAqB,EACrB,OAAqB;IAErB,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC;QAC9B,OAAO,EAAE,GAAG,OAAO,CAAC,WAAW,8CAA8C;QAC7E,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAChC,IAAI,EAAE,GAAG,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;YAC9E,KAAK,EAAE,MAAM,CAAC,EAAE;YAChB,OAAO,EAAE,MAAM,CAAC,gBAAgB,IAAI,CAAC,MAAM,CAAC,SAAS;SACtD,CAAC,CAAC;QACH,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,aAA8B;IACvE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAiB;QAC1C,OAAO,EAAE,kBAAkB;QAC3B,OAAO,EAAE,aAAa;QACtB,OAAO,EAAE;YACP;gBACE,KAAK,EAAE,UAAU;gBACjB,IAAI,EAAE,+BAA+B;aACtC;YACD;gBACE,KAAK,EAAE,WAAW;gBAClB,IAAI,EAAE,6BAA6B;aACpC;YACD;gBACE,KAAK,EAAE,SAAS;gBAChB,IAAI,EAAE,4BAA4B;aACnC;SACF;KACF,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAoB,EACpB,QAAsB;IAEtB,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QAC7C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAkB;YAC3C,OAAO,EAAE,OAAO,QAAQ,CAAC,OAAO,EAAE;YAClC,OAAO,EAAE;gBACP,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE;gBACrC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;aAChC;SACF,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAkB;QAC3C,OAAO,EAAE,OAAO,QAAQ,CAAC,OAAO,EAAE;QAClC,OAAO,EAAE;YACP,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE;YACxC,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE;YACzC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;SAChC;KACF,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,14 @@
1
+ export interface ListedFile {
2
+ absPath: string;
3
+ relPath: string;
4
+ mtimeMs: number;
5
+ }
6
+ export interface FileStat {
7
+ mtimeMs: number;
8
+ }
9
+ export declare function exists(absPath: string): Promise<boolean>;
10
+ export declare function statFile(absPath: string): Promise<FileStat | undefined>;
11
+ export declare function ensureDir(absPath: string): Promise<void>;
12
+ export declare function listFilesRecursive(basePath: string): Promise<ListedFile[]>;
13
+ export declare function resetDirectoryContents(basePath: string): Promise<void>;
14
+ export declare function copySingleFile(src: string, dest: string): Promise<void>;