@nepopsx/cli 0.0.23 → 0.0.25

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 (132) hide show
  1. package/dist/commands/guard.d.ts +10 -0
  2. package/dist/commands/guard.d.ts.map +1 -0
  3. package/dist/commands/guard.js +63 -0
  4. package/dist/commands/guard.js.map +1 -0
  5. package/dist/commands/import-agents.d.ts +17 -0
  6. package/dist/commands/import-agents.d.ts.map +1 -0
  7. package/dist/commands/import-agents.js +166 -0
  8. package/dist/commands/import-agents.js.map +1 -0
  9. package/dist/commands/import.d.ts +19 -0
  10. package/dist/commands/import.d.ts.map +1 -0
  11. package/dist/commands/import.js +175 -0
  12. package/dist/commands/import.js.map +1 -0
  13. package/dist/commands/init.d.ts.map +1 -1
  14. package/dist/commands/init.js +22 -14
  15. package/dist/commands/init.js.map +1 -1
  16. package/dist/commands/install.js +4 -4
  17. package/dist/commands/install.js.map +1 -1
  18. package/dist/commands/login.d.ts +3 -3
  19. package/dist/commands/login.d.ts.map +1 -1
  20. package/dist/commands/login.js +26 -70
  21. package/dist/commands/login.js.map +1 -1
  22. package/dist/commands/push-learnings.js +1 -1
  23. package/dist/commands/push-learnings.js.map +1 -1
  24. package/dist/commands/sync.d.ts.map +1 -1
  25. package/dist/commands/sync.js +7 -2
  26. package/dist/commands/sync.js.map +1 -1
  27. package/dist/commands/up.js +2 -2
  28. package/dist/commands/up.js.map +1 -1
  29. package/dist/config/api-config.d.ts +7 -0
  30. package/dist/config/api-config.d.ts.map +1 -1
  31. package/dist/config/api-config.js +9 -1
  32. package/dist/config/api-config.js.map +1 -1
  33. package/dist/config/global-config.d.ts +52 -0
  34. package/dist/config/global-config.d.ts.map +1 -0
  35. package/dist/config/global-config.js +161 -0
  36. package/dist/config/global-config.js.map +1 -0
  37. package/dist/config/global-config.test.d.ts +2 -0
  38. package/dist/config/global-config.test.d.ts.map +1 -0
  39. package/dist/config/global-config.test.js +62 -0
  40. package/dist/config/global-config.test.js.map +1 -0
  41. package/dist/guard/policy.d.ts +38 -0
  42. package/dist/guard/policy.d.ts.map +1 -0
  43. package/dist/guard/policy.js +62 -0
  44. package/dist/guard/policy.js.map +1 -0
  45. package/dist/guard/policy.test.d.ts +2 -0
  46. package/dist/guard/policy.test.d.ts.map +1 -0
  47. package/dist/guard/policy.test.js +47 -0
  48. package/dist/guard/policy.test.js.map +1 -0
  49. package/dist/hooks/capture-hooks.d.ts.map +1 -1
  50. package/dist/hooks/capture-hooks.js +36 -1
  51. package/dist/hooks/capture-hooks.js.map +1 -1
  52. package/dist/import/adapter.d.ts +82 -0
  53. package/dist/import/adapter.d.ts.map +1 -0
  54. package/dist/import/adapter.js +111 -0
  55. package/dist/import/adapter.js.map +1 -0
  56. package/dist/import/adapter.test.d.ts +2 -0
  57. package/dist/import/adapter.test.d.ts.map +1 -0
  58. package/dist/import/adapter.test.js +100 -0
  59. package/dist/import/adapter.test.js.map +1 -0
  60. package/dist/import/agents/agent-adapter.d.ts +83 -0
  61. package/dist/import/agents/agent-adapter.d.ts.map +1 -0
  62. package/dist/import/agents/agent-adapter.js +66 -0
  63. package/dist/import/agents/agent-adapter.js.map +1 -0
  64. package/dist/import/agents/agent-adapter.test.d.ts +2 -0
  65. package/dist/import/agents/agent-adapter.test.d.ts.map +1 -0
  66. package/dist/import/agents/agent-adapter.test.js +99 -0
  67. package/dist/import/agents/agent-adapter.test.js.map +1 -0
  68. package/dist/import/agents/artifact-parser.d.ts +26 -0
  69. package/dist/import/agents/artifact-parser.d.ts.map +1 -0
  70. package/dist/import/agents/artifact-parser.js +40 -0
  71. package/dist/import/agents/artifact-parser.js.map +1 -0
  72. package/dist/import/agents/assembler.d.ts +32 -0
  73. package/dist/import/agents/assembler.d.ts.map +1 -0
  74. package/dist/import/agents/assembler.js +62 -0
  75. package/dist/import/agents/assembler.js.map +1 -0
  76. package/dist/import/agents/assembler.test.d.ts +2 -0
  77. package/dist/import/agents/assembler.test.d.ts.map +1 -0
  78. package/dist/import/agents/assembler.test.js +115 -0
  79. package/dist/import/agents/assembler.test.js.map +1 -0
  80. package/dist/import/agents/claude-code-adapter.d.ts +11 -0
  81. package/dist/import/agents/claude-code-adapter.d.ts.map +1 -0
  82. package/dist/import/agents/claude-code-adapter.js +67 -0
  83. package/dist/import/agents/claude-code-adapter.js.map +1 -0
  84. package/dist/import/agents/copilot-agent-adapter.d.ts +12 -0
  85. package/dist/import/agents/copilot-agent-adapter.d.ts.map +1 -0
  86. package/dist/import/agents/copilot-agent-adapter.js +89 -0
  87. package/dist/import/agents/copilot-agent-adapter.js.map +1 -0
  88. package/dist/import/agents/scanner.d.ts +15 -0
  89. package/dist/import/agents/scanner.d.ts.map +1 -0
  90. package/dist/import/agents/scanner.js +87 -0
  91. package/dist/import/agents/scanner.js.map +1 -0
  92. package/dist/import/agents/secret-scan.d.ts +14 -0
  93. package/dist/import/agents/secret-scan.d.ts.map +1 -0
  94. package/dist/import/agents/secret-scan.js +64 -0
  95. package/dist/import/agents/secret-scan.js.map +1 -0
  96. package/dist/import/agents/secret-scan.test.d.ts +2 -0
  97. package/dist/import/agents/secret-scan.test.d.ts.map +1 -0
  98. package/dist/import/agents/secret-scan.test.js +41 -0
  99. package/dist/import/agents/secret-scan.test.js.map +1 -0
  100. package/dist/import/claude-memory-adapter.d.ts +20 -0
  101. package/dist/import/claude-memory-adapter.d.ts.map +1 -0
  102. package/dist/import/claude-memory-adapter.js +87 -0
  103. package/dist/import/claude-memory-adapter.js.map +1 -0
  104. package/dist/import/copilot-adapter.d.ts +13 -0
  105. package/dist/import/copilot-adapter.d.ts.map +1 -0
  106. package/dist/import/copilot-adapter.js +75 -0
  107. package/dist/import/copilot-adapter.js.map +1 -0
  108. package/dist/index.js +28 -7
  109. package/dist/index.js.map +1 -1
  110. package/dist/learnings/memory-index.d.ts +17 -0
  111. package/dist/learnings/memory-index.d.ts.map +1 -0
  112. package/dist/learnings/memory-index.js +73 -0
  113. package/dist/learnings/memory-index.js.map +1 -0
  114. package/dist/licensing/index.d.ts +1 -1
  115. package/dist/licensing/index.d.ts.map +1 -1
  116. package/dist/licensing/index.js +1 -1
  117. package/dist/licensing/index.js.map +1 -1
  118. package/dist/licensing/installer.d.ts +7 -8
  119. package/dist/licensing/installer.d.ts.map +1 -1
  120. package/dist/licensing/installer.js +9 -17
  121. package/dist/licensing/installer.js.map +1 -1
  122. package/dist/licensing/license-manager.d.ts +25 -51
  123. package/dist/licensing/license-manager.d.ts.map +1 -1
  124. package/dist/licensing/license-manager.js +54 -275
  125. package/dist/licensing/license-manager.js.map +1 -1
  126. package/dist/licensing/workspace-name.d.ts +1 -1
  127. package/dist/licensing/workspace-name.js +1 -1
  128. package/dist/mcp/config-generator.d.ts +6 -6
  129. package/dist/mcp/config-generator.d.ts.map +1 -1
  130. package/dist/mcp/config-generator.js +4 -4
  131. package/dist/mcp/config-generator.js.map +1 -1
  132. package/package.json +1 -1
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `nepopsx guard` — a Claude Code PreToolUse hook. Reads the tool call from stdin,
3
+ * evaluates it against the local policy, and emits a `permissionDecision: deny`
4
+ * (which blocks the call) when a rule matches. NO network on the hot path.
5
+ *
6
+ * SOFT-FAIL by design: any error in the guard itself exits cleanly (fail-open) so it
7
+ * can never crash or hang the calling session. Only an explicit rule match blocks.
8
+ */
9
+ export declare function guardCommand(): Promise<void>;
10
+ //# sourceMappingURL=guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/commands/guard.ts"],"names":[],"mappings":"AA0BA;;;;;;;GAOG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAgClD"}
@@ -0,0 +1,63 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { BUILTIN_RULES, evaluate, validRule } from '../guard/policy.js';
4
+ /** Read all of stdin (the hook payload). */
5
+ async function readStdin() {
6
+ const chunks = [];
7
+ for await (const chunk of process.stdin)
8
+ chunks.push(chunk);
9
+ return Buffer.concat(chunks).toString('utf-8');
10
+ }
11
+ /** Built-in rules + the locally-cached `.nepopsx/policy.json` (synced out-of-band). */
12
+ function loadRules(cwd) {
13
+ const rules = [...BUILTIN_RULES];
14
+ const policyPath = resolve(cwd, '.nepopsx', 'policy.json');
15
+ if (existsSync(policyPath)) {
16
+ try {
17
+ const parsed = JSON.parse(readFileSync(policyPath, 'utf-8'));
18
+ if (Array.isArray(parsed.rules))
19
+ rules.push(...parsed.rules.filter(validRule));
20
+ }
21
+ catch {
22
+ /* fail-open: a corrupt policy file must never break the session */
23
+ }
24
+ }
25
+ return rules;
26
+ }
27
+ /**
28
+ * `nepopsx guard` — a Claude Code PreToolUse hook. Reads the tool call from stdin,
29
+ * evaluates it against the local policy, and emits a `permissionDecision: deny`
30
+ * (which blocks the call) when a rule matches. NO network on the hot path.
31
+ *
32
+ * SOFT-FAIL by design: any error in the guard itself exits cleanly (fail-open) so it
33
+ * can never crash or hang the calling session. Only an explicit rule match blocks.
34
+ */
35
+ export async function guardCommand() {
36
+ try {
37
+ const raw = await readStdin();
38
+ if (!raw.trim())
39
+ return;
40
+ const payload = JSON.parse(raw);
41
+ const cwd = typeof payload.cwd === 'string' && payload.cwd ? payload.cwd : process.cwd();
42
+ const input = {
43
+ tool_name: typeof payload.tool_name === 'string' ? payload.tool_name : '',
44
+ tool_input: payload.tool_input ?? {},
45
+ };
46
+ const verdict = evaluate(input, loadRules(cwd));
47
+ if (verdict.decision === 'deny' && verdict.rule) {
48
+ // permissionDecision:deny blocks the tool call; the reason is shown to the agent.
49
+ process.stdout.write(`${JSON.stringify({
50
+ hookSpecificOutput: {
51
+ hookEventName: 'PreToolUse',
52
+ permissionDecision: 'deny',
53
+ permissionDecisionReason: `[nepopsx policy:${verdict.rule.id}] ${verdict.rule.reason}`,
54
+ },
55
+ })}\n`);
56
+ }
57
+ // allow → no output, exit 0
58
+ }
59
+ catch {
60
+ /* fail-open */
61
+ }
62
+ }
63
+ //# sourceMappingURL=guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.js","sourceRoot":"","sources":["../../src/commands/guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAoC,MAAM,oBAAoB,CAAC;AAE1G,4CAA4C;AAC5C,KAAK,UAAU,SAAS;IACtB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK;QAAE,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC;IACtE,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACjD,CAAC;AAED,uFAAuF;AACvF,SAAS,SAAS,CAAC,GAAW;IAC5B,MAAM,KAAK,GAAG,CAAC,GAAG,aAAa,CAAC,CAAC;IACjC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;IAC3D,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAA0B,CAAC;YACtF,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QACjF,CAAC;QAAC,MAAM,CAAC;YACP,mEAAmE;QACrE,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;YAAE,OAAO;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAI7B,CAAC;QACF,MAAM,GAAG,GAAG,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QACzF,MAAM,KAAK,GAAe;YACxB,SAAS,EAAE,OAAO,OAAO,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;YACzE,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,EAAE;SACrC,CAAC;QAEF,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QAChD,IAAI,OAAO,CAAC,QAAQ,KAAK,MAAM,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YAChD,kFAAkF;YAClF,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,IAAI,CAAC,SAAS,CAAC;gBAChB,kBAAkB,EAAE;oBAClB,aAAa,EAAE,YAAY;oBAC3B,kBAAkB,EAAE,MAAM;oBAC1B,wBAAwB,EAAE,mBAAmB,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE;iBACvF;aACF,CAAC,IAAI,CACP,CAAC;QACJ,CAAC;QACD,4BAA4B;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,eAAe;IACjB,CAAC;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ interface ImportAgentsOptions {
2
+ config: string;
3
+ workspace?: string;
4
+ dryRun?: boolean;
5
+ }
6
+ /**
7
+ * `nepopsx import-agents` — comprehend a customer's existing custom agents
8
+ * (.claude/agents, .github/agents) into the platform as governed PENDING bundles.
9
+ *
10
+ * Scans both ecosystems, assembles agent-centric bundles (orchestration graph +
11
+ * dangling-ref flags), redacts secrets locally, then POSTs in size-bounded batches to
12
+ * /agents/import. Foreign agents are untrusted: every bundle lands PENDING (or
13
+ * QUARANTINED on a security-scan hit) for review — never auto-blessed.
14
+ */
15
+ export declare function importAgentsCommand(options: ImportAgentsOptions): Promise<void>;
16
+ export {};
17
+ //# sourceMappingURL=import-agents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-agents.d.ts","sourceRoot":"","sources":["../../src/commands/import-agents.ts"],"names":[],"mappings":"AAYA,UAAU,mBAAmB;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAqED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+FrF"}
@@ -0,0 +1,166 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { parse as parseYaml } from 'yaml';
4
+ import chalk from 'chalk';
5
+ import { resolveApiBase } from '../config/api-config.js';
6
+ import { readLicense, resolveWorkspaceName } from '../licensing/index.js';
7
+ import { fetchWithTimeout } from '../utils/fetch.js';
8
+ import { DOWNLOAD_TIMEOUT_MS } from '../constants.js';
9
+ import { scanRepo } from '../import/agents/scanner.js';
10
+ import { assembleBundles } from '../import/agents/assembler.js';
11
+ import { redactSecrets, redactValue } from '../import/agents/secret-scan.js';
12
+ /** Conservative per-request budget — the /agents/import body limit 413s on big repos. */
13
+ const MAX_REQUEST_BYTES = 60_000;
14
+ /** Serialize one assembled bundle into the import payload, redacting secrets first. */
15
+ function toPayload(b) {
16
+ const inst = redactSecrets(b.agent.instructions);
17
+ const rawR = redactSecrets(b.agent.raw);
18
+ const extraR = redactValue(b.agent.extra);
19
+ const redactions = inst.count + rawR.count + extraR.count;
20
+ const fidelity = [
21
+ ...b.fidelity,
22
+ ...b.agent.fidelity,
23
+ ...(redactions > 0
24
+ ? [{ field: 'secrets', severity: 'loss', detail: `Redacted ${redactions} secret(s) before import.` }]
25
+ : []),
26
+ ];
27
+ return {
28
+ redactions,
29
+ payload: {
30
+ slug: b.agent.slug,
31
+ name: b.agent.name,
32
+ kind: b.agent.kind,
33
+ description: b.agent.description,
34
+ originProvider: b.agent.originProvider,
35
+ instructions: inst.value,
36
+ importedFrom: b.agent.importedFrom,
37
+ fidelity,
38
+ ir: {
39
+ agent: {
40
+ modelRaw: b.agent.modelRaw,
41
+ tools: b.agent.tools,
42
+ disallowedTools: b.agent.disallowedTools,
43
+ subAgents: b.agent.subAgents,
44
+ handoffs: b.agent.handoffs,
45
+ userInvocable: b.agent.userInvocable,
46
+ target: b.agent.target,
47
+ extra: extraR.value,
48
+ raw: rawR.value,
49
+ },
50
+ graph: b.graph,
51
+ skills: b.skills.map((s) => s.slug),
52
+ },
53
+ },
54
+ };
55
+ }
56
+ /** Greedily batch payloads so each POST body stays under the size limit (413 fix). */
57
+ function chunkByBytes(items, maxBytes) {
58
+ const out = [];
59
+ let cur = [];
60
+ let size = 2; // "[]"
61
+ for (const it of items) {
62
+ const s = JSON.stringify(it).length + 1;
63
+ if (cur.length > 0 && size + s > maxBytes) {
64
+ out.push(cur);
65
+ cur = [];
66
+ size = 2;
67
+ }
68
+ cur.push(it);
69
+ size += s;
70
+ }
71
+ if (cur.length > 0)
72
+ out.push(cur);
73
+ return out;
74
+ }
75
+ /**
76
+ * `nepopsx import-agents` — comprehend a customer's existing custom agents
77
+ * (.claude/agents, .github/agents) into the platform as governed PENDING bundles.
78
+ *
79
+ * Scans both ecosystems, assembles agent-centric bundles (orchestration graph +
80
+ * dangling-ref flags), redacts secrets locally, then POSTs in size-bounded batches to
81
+ * /agents/import. Foreign agents are untrusted: every bundle lands PENDING (or
82
+ * QUARANTINED on a security-scan hit) for review — never auto-blessed.
83
+ */
84
+ export async function importAgentsCommand(options) {
85
+ const cwd = process.cwd();
86
+ let config = {};
87
+ const configPath = resolve(cwd, options.config);
88
+ if (existsSync(configPath)) {
89
+ try {
90
+ const raw = parseYaml(readFileSync(configPath, 'utf-8'));
91
+ if (raw && typeof raw === 'object')
92
+ config = raw;
93
+ }
94
+ catch {
95
+ /* best-effort */
96
+ }
97
+ }
98
+ const bundles = assembleBundles(scanRepo(cwd));
99
+ if (bundles.length === 0) {
100
+ console.log(chalk.dim('nepopsx import-agents: no agents found under .claude/agents or .github/agents.'));
101
+ return;
102
+ }
103
+ const serialized = bundles.map(toPayload);
104
+ const totalRedactions = serialized.reduce((n, s) => n + s.redactions, 0);
105
+ const dangling = bundles.reduce((n, b) => n + b.graph.filter((e) => !e.resolvedInSet).length, 0);
106
+ // ── Dry run: report locally, no auth, no POST ──────────────────────────────
107
+ if (options.dryRun) {
108
+ console.log(chalk.bold.cyan(`\n🔎 nepopsx import-agents — dry run (${bundles.length} bundle(s))\n`));
109
+ for (const b of bundles) {
110
+ const tag = b.agent.kind === 'command' ? chalk.magenta('orchestrator') : chalk.dim('agent');
111
+ const edges = b.graph.length ? ` graph[${b.graph.map((e) => e.to + (e.resolvedInSet ? '' : ' ✗')).join(', ')}]` : '';
112
+ console.log(` ${chalk.bold(b.agent.slug)} ${tag} ${chalk.dim(`[${b.agent.originProvider}]`)}${edges}`);
113
+ console.log(` ${chalk.dim(b.agent.importedFrom)}`);
114
+ }
115
+ const batches = chunkByBytes(serialized.map((s) => s.payload), MAX_REQUEST_BYTES);
116
+ console.log(chalk.dim(`\n ${totalRedactions} secret(s) would be redacted · ${dangling} dangling ref(s) · ${batches.length} batch(es).`));
117
+ console.log(chalk.dim(' No changes sent. Re-run without --dry-run to import as PENDING for review.\n'));
118
+ return;
119
+ }
120
+ // ── Real run: auth + workspace, then POST in batches ───────────────────────
121
+ const license = readLicense(cwd);
122
+ if (!license) {
123
+ console.error(chalk.red('nepopsx import-agents: not logged in. Run `nepopsx login` first.'));
124
+ process.exitCode = 1;
125
+ return;
126
+ }
127
+ const workspace = options.workspace ?? resolveWorkspaceName(cwd, license, config);
128
+ if (!workspace || workspace === 'unknown') {
129
+ console.error(chalk.red('nepopsx import-agents: could not resolve a workspace. Pass --workspace.'));
130
+ process.exitCode = 1;
131
+ return;
132
+ }
133
+ const apiBase = resolveApiBase(cwd);
134
+ const batches = chunkByBytes(serialized.map((s) => s.payload), MAX_REQUEST_BYTES);
135
+ let received = 0;
136
+ let pending = 0;
137
+ let quarantined = 0;
138
+ try {
139
+ for (const [i, batch] of batches.entries()) {
140
+ const response = await fetchWithTimeout(`${apiBase}/agents/import`, {
141
+ method: 'POST',
142
+ headers: { Authorization: `Bearer ${license.key}`, 'Content-Type': 'application/json' },
143
+ body: JSON.stringify({ workspace, bundles: batch }),
144
+ }, DOWNLOAD_TIMEOUT_MS);
145
+ if (!response.ok) {
146
+ const body = await response.text().catch(() => '');
147
+ console.error(chalk.red(`nepopsx import-agents: batch ${i + 1}/${batches.length} → ${response.status} ${body.slice(0, 200)}`));
148
+ process.exitCode = 1;
149
+ return;
150
+ }
151
+ const json = (await response.json());
152
+ received += json.received ?? 0;
153
+ pending += json.pending ?? 0;
154
+ quarantined += json.quarantined ?? 0;
155
+ }
156
+ }
157
+ catch (err) {
158
+ console.error(chalk.red(`nepopsx import-agents: failed — ${err instanceof Error ? err.message : String(err)}`));
159
+ process.exitCode = 1;
160
+ return;
161
+ }
162
+ console.log(chalk.green(`\n✅ nepopsx import-agents: ${received} imported → ${pending} pending, ${quarantined} quarantined ` +
163
+ `(${totalRedactions} secret(s) redacted, ${batches.length} batch(es)).`));
164
+ console.log(chalk.dim(' Review pending agents in the dashboard before they render.'));
165
+ }
166
+ //# sourceMappingURL=import-agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-agents.js","sourceRoot":"","sources":["../../src/commands/import-agents.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ interface ImportOptions {
2
+ config: string;
3
+ workspace?: string;
4
+ source: string;
5
+ agent?: string;
6
+ dryRun?: boolean;
7
+ force?: boolean;
8
+ }
9
+ /**
10
+ * `nepopsx import` — ingest agent-memory files written by OTHER tools (GitHub
11
+ * Copilot instructions, Claude project memory) into the platform as PENDING
12
+ * learnings, routed to the resolved org/workspace and scoped by service.
13
+ *
14
+ * Governance: every imported learning is sent with frequency=1 so it can never
15
+ * auto-approve — it always lands in the review queue. Foreign memory is untrusted.
16
+ */
17
+ export declare function importCommand(options: ImportOptions): Promise<void>;
18
+ export {};
19
+ //# sourceMappingURL=import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../src/commands/import.ts"],"names":[],"mappings":"AAeA,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAeD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAuLzE"}
@@ -0,0 +1,175 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { parse as parseYaml } from 'yaml';
4
+ import chalk from 'chalk';
5
+ import { resolveApiBase } from '../config/api-config.js';
6
+ import { readLicense, resolveWorkspaceName } from '../licensing/index.js';
7
+ import { fetchWithTimeout } from '../utils/fetch.js';
8
+ import { DOWNLOAD_TIMEOUT_MS } from '../constants.js';
9
+ import { writeYamlLearning } from '../learnings/yaml-learnings.js';
10
+ import { regenerateMemoryIndex } from '../learnings/memory-index.js';
11
+ import { copilotAdapter } from '../import/copilot-adapter.js';
12
+ import { claudeMemoryAdapter } from '../import/claude-memory-adapter.js';
13
+ const ADAPTERS = [copilotAdapter, claudeMemoryAdapter];
14
+ /** Map an adapter's source tag to the constrained LearningYaml.source union. */
15
+ function provenanceSource(adapterId) {
16
+ return adapterId === 'claude-memory' ? 'claude-auto-memory' : 'manual';
17
+ }
18
+ /**
19
+ * `nepopsx import` — ingest agent-memory files written by OTHER tools (GitHub
20
+ * Copilot instructions, Claude project memory) into the platform as PENDING
21
+ * learnings, routed to the resolved org/workspace and scoped by service.
22
+ *
23
+ * Governance: every imported learning is sent with frequency=1 so it can never
24
+ * auto-approve — it always lands in the review queue. Foreign memory is untrusted.
25
+ */
26
+ export async function importCommand(options) {
27
+ const cwd = process.cwd();
28
+ // Load workspace config (services for scope inference + workspace name).
29
+ let config = {};
30
+ const configPath = resolve(cwd, options.config);
31
+ if (existsSync(configPath)) {
32
+ try {
33
+ const raw = parseYaml(readFileSync(configPath, 'utf-8'));
34
+ if (raw && typeof raw === 'object')
35
+ config = raw;
36
+ }
37
+ catch {
38
+ /* best-effort */
39
+ }
40
+ }
41
+ const services = Array.isArray(config.services)
42
+ ? config.services
43
+ .filter((s) => typeof s?.name === 'string')
44
+ .map((s) => ({ name: s.name, path: s.path }))
45
+ : [];
46
+ const ctx = { rootDir: cwd, services };
47
+ // Select adapters.
48
+ const wanted = options.source === 'all' ? ADAPTERS.map((a) => a.id) : [options.source];
49
+ const selected = ADAPTERS.filter((a) => wanted.includes(a.id));
50
+ if (selected.length === 0) {
51
+ console.error(chalk.red(`Unknown --source "${options.source}". Use: copilot | claude-memory | all.`));
52
+ process.exitCode = 1;
53
+ return;
54
+ }
55
+ // Parse all candidates.
56
+ const importedDir = resolve(cwd, '.nepopsx', 'imported');
57
+ const candidates = [];
58
+ let skippedExisting = 0;
59
+ for (const adapter of selected) {
60
+ const agent = options.agent ?? adapter.id;
61
+ const files = adapter.detect(ctx);
62
+ for (const file of files) {
63
+ for (const raw of adapter.parse(file, ctx)) {
64
+ // Idempotency: skip a candidate already imported (unless --force).
65
+ const marker = resolve(importedDir, adapter.id, `${raw.slug}.yaml`);
66
+ if (!options.force && existsSync(marker)) {
67
+ skippedExisting++;
68
+ continue;
69
+ }
70
+ candidates.push({ adapterId: adapter.id, agent, raw });
71
+ }
72
+ }
73
+ }
74
+ if (candidates.length === 0) {
75
+ console.log(chalk.dim(`nepopsx import: nothing new to import` +
76
+ (skippedExisting > 0 ? ` (${skippedExisting} already imported — use --force to re-import).` : '.')));
77
+ return;
78
+ }
79
+ // ── Dry run: report and exit, no POST ──────────────────────────────────────
80
+ if (options.dryRun) {
81
+ console.log(chalk.bold.cyan(`\n🔎 nepopsx import — dry run (${candidates.length} candidate(s))\n`));
82
+ for (const c of candidates) {
83
+ const scope = c.raw.services && c.raw.services.length > 0 ? c.raw.services.join(', ') : 'workspace-wide';
84
+ console.log(` ${chalk.bold(c.raw.slug)} ${chalk.dim(`[${c.adapterId} → ${scope}]`)}`);
85
+ console.log(` ${chalk.dim(c.raw.importedFrom)}`);
86
+ }
87
+ if (skippedExisting > 0) {
88
+ console.log(chalk.dim(`\n (${skippedExisting} already imported; skipped.)`));
89
+ }
90
+ console.log(chalk.dim('\n No changes written. Re-run without --dry-run to import as pending.\n'));
91
+ return;
92
+ }
93
+ // ── Real run: require auth + a resolved org/workspace ───────────────────────
94
+ const license = readLicense(cwd);
95
+ if (!license) {
96
+ console.error(chalk.red('nepopsx import: not logged in. Run `nepopsx login` first.'));
97
+ process.exitCode = 1;
98
+ return;
99
+ }
100
+ const workspace = options.workspace ?? resolveWorkspaceName(cwd, license, config);
101
+ if (!workspace || workspace === 'unknown') {
102
+ console.error(chalk.red('nepopsx import: could not resolve a workspace. Set workspace.name in workspace.yaml or pass --workspace.'));
103
+ process.exitCode = 1;
104
+ return;
105
+ }
106
+ if (!license.org) {
107
+ console.error(chalk.red('nepopsx import: could not resolve an org for this project. Run `nepopsx login` here, ' +
108
+ 'or pin the org in workspace.yaml.'));
109
+ process.exitCode = 1;
110
+ return;
111
+ }
112
+ const namespace = `${license.org}/${workspace}`;
113
+ const apiBase = resolveApiBase(cwd);
114
+ // frequency=1 ⇒ low confidence ⇒ backend lands it PENDING (never auto-approved).
115
+ const patterns = candidates.map((c) => ({
116
+ type: c.raw.type ?? 'custom_instruction',
117
+ slug: c.raw.slug,
118
+ title: c.raw.title,
119
+ content: c.raw.content,
120
+ agent: c.agent,
121
+ applies_to: c.raw.appliesTo ?? [],
122
+ services: c.raw.services ?? [],
123
+ source: c.raw.source,
124
+ frequency: 1,
125
+ config_path: c.raw.configPath,
126
+ config_value: c.raw.configValue,
127
+ }));
128
+ let results = [];
129
+ try {
130
+ const response = await fetchWithTimeout(`${apiBase}/learnings/auto`, {
131
+ method: 'POST',
132
+ headers: { Authorization: `Bearer ${license.key}`, 'Content-Type': 'application/json' },
133
+ body: JSON.stringify({ workspace, namespace, patterns }),
134
+ }, DOWNLOAD_TIMEOUT_MS);
135
+ if (!response.ok) {
136
+ const body = await response.text().catch(() => '');
137
+ console.error(chalk.red(`nepopsx import: backend ${response.status} — ${body.slice(0, 200)}`));
138
+ process.exitCode = 1;
139
+ return;
140
+ }
141
+ const json = (await response.json());
142
+ results = json.results ?? [];
143
+ // Write provenance YAML per candidate, stamped with the server's verdict.
144
+ const verdictBySlug = new Map(results.map((r) => [r.slug, r.status]));
145
+ for (const c of candidates) {
146
+ const status = verdictBySlug.get(c.raw.slug);
147
+ const yaml = {
148
+ slug: c.raw.slug,
149
+ type: (c.raw.type ?? 'custom_instruction'),
150
+ confidence: 'low',
151
+ agent: c.agent,
152
+ applies_to: c.raw.appliesTo ?? [],
153
+ services: c.raw.services ?? [],
154
+ status: status === 'rejected' ? 'reverted' : status === 'approved' ? 'approved' : 'pending',
155
+ content: c.raw.content,
156
+ evidence: `Imported from ${c.raw.importedFrom} via ${c.raw.source}`,
157
+ source: provenanceSource(c.adapterId),
158
+ created_at: new Date().toISOString(),
159
+ };
160
+ writeYamlLearning(resolve(importedDir, c.adapterId), yaml);
161
+ }
162
+ console.log(chalk.green(`\n✅ nepopsx import: ${json.received ?? patterns.length} imported → ` +
163
+ `${json.pending ?? 0} pending, ${json.auto_applied ?? 0} applied, ${json.rejected ?? 0} rejected (scanned).`));
164
+ console.log(chalk.dim(' Review pending imports in the dashboard, or `nepopsx sync` once approved.'));
165
+ }
166
+ catch (err) {
167
+ console.error(chalk.red(`nepopsx import: failed — ${err instanceof Error ? err.message : String(err)}`));
168
+ process.exitCode = 1;
169
+ return;
170
+ }
171
+ // Refresh the human-scannable index.
172
+ const index = regenerateMemoryIndex(cwd);
173
+ console.log(chalk.dim(` MEMORY.md updated (${index.count} learnings indexed).\n`));
174
+ }
175
+ //# sourceMappingURL=import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import.js","sourceRoot":"","sources":["../../src/commands/import.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAaA,UAAU,WAAW;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AA4ND,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA8JrE"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAaA,UAAU,WAAW;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AA+ND,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA8JrE"}
@@ -10,15 +10,23 @@ import { resolveApiBase } from '../config/api-config.js';
10
10
  import { API_TIMEOUT_MS, DOWNLOAD_TIMEOUT_MS } from '../constants.js';
11
11
  import { fetchEntitledAgents } from '../agents/catalog.js';
12
12
  // ─── Helpers ─────────────────────────────────────────────────────────────────
13
- function readStoredConfig(rootDir) {
14
- const p = join(rootDir, '.nepopsx', 'config.json');
15
- if (!existsSync(p))
16
- return {};
13
+ /**
14
+ * Ensure the repo `.gitignore` ignores `.nepopsx/config.json`. The device token
15
+ * lives in `~/.nepopsx` now, but this guards any pre-migration leftover and the
16
+ * non-secret local config from being committed. Best-effort.
17
+ */
18
+ function ensureGitignoreGuard(rootDir) {
19
+ const guard = '.nepopsx/config.json';
20
+ const gitignorePath = join(rootDir, '.gitignore');
17
21
  try {
18
- return JSON.parse(readFileSync(p, 'utf-8'));
22
+ const existing = existsSync(gitignorePath) ? readFileSync(gitignorePath, 'utf-8') : '';
23
+ if (existing.split(/\r?\n/).some((line) => line.trim() === guard))
24
+ return;
25
+ const prefix = existing.length > 0 && !existing.endsWith('\n') ? '\n' : '';
26
+ writeFileSync(gitignorePath, `${existing}${prefix}# nepopsx — never commit credentials\n${guard}\n`, 'utf-8');
19
27
  }
20
28
  catch {
21
- return {};
29
+ /* best-effort */
22
30
  }
23
31
  }
24
32
  async function tryListRemoteWorkspaces(cwd, licenseKey) {
@@ -143,7 +151,7 @@ function printNextSteps(scenario, extra) {
143
151
  console.log(` 2. Enrich repo: ${chalk.cyan('nepopsx scan')}`);
144
152
  console.log(` 3. Install agent: ${chalk.cyan('nepopsx install feature-factory')}`);
145
153
  console.log(` 4. Generate files: ${chalk.cyan('nepopsx sync')}`);
146
- console.log(` 5. Share with team: Run ${chalk.cyan('nepopsx init')} again and choose "Push to org"\n (requires ${chalk.cyan('nepopsx activate <key>')} first)`);
154
+ console.log(` 5. Share with team: Run ${chalk.cyan('nepopsx login')} and then run ${chalk.cyan('nepopsx init')} again`);
147
155
  break;
148
156
  case 'pushed-team':
149
157
  console.log(` 1. Review config: ${chalk.cyan('cat .nepopsx/workspace.yaml')}`);
@@ -162,8 +170,8 @@ function printNextSteps(scenario, extra) {
162
170
  break;
163
171
  case 'local-no-license':
164
172
  console.log(` 1. Review config: ${chalk.cyan('cat .nepopsx/workspace.yaml')}`);
165
- console.log(` 2. Get a license: ${chalk.cyan('https://nepopsx.dev/pricing')}`);
166
- console.log(` 3. Activate it: ${chalk.cyan('nepopsx activate <your-license-key>')}`);
173
+ console.log(` 2. Choose a plan: ${chalk.cyan('https://nepopsx.dev/pricing')}`);
174
+ console.log(` 3. Connect machine:${chalk.cyan('nepopsx login')}`);
167
175
  console.log(` 4. Enrich repo: ${chalk.cyan('nepopsx scan')}`);
168
176
  console.log(` 5. Install agent: ${chalk.cyan('nepopsx install feature-factory')}`);
169
177
  console.log(` 6. Generate files: ${chalk.cyan('nepopsx sync')}`);
@@ -200,12 +208,12 @@ export async function initCommand(options) {
200
208
  console.log(chalk.bold.cyan('\n🔧 NEPOPSX Workspace Setup\n'));
201
209
  // ── Probe auth state ──────────────────────────────────────────────────────
202
210
  const license = readLicense(cwd);
203
- const storedConfig = readStoredConfig(cwd);
204
- const orgSlug = storedConfig.auth?.org;
211
+ const orgSlug = license?.org || undefined;
205
212
  const apiBase = resolveApiBase(cwd);
213
+ ensureGitignoreGuard(cwd);
206
214
  if (!license) {
207
215
  // ── No license: local-only setup ────────────────────────────────────────
208
- console.warn(chalk.yellow('⚠ No license key found (.nepopsx/license.json missing).'));
216
+ console.warn(chalk.yellow('⚠ Not logged in run `nepopsx login` to sync with your team.'));
209
217
  console.log(chalk.dim(' Workspace will be set up locally (personal use only).\n'));
210
218
  const choice = await select({
211
219
  message: 'How do you want to proceed?',
@@ -216,8 +224,8 @@ export async function initCommand(options) {
216
224
  });
217
225
  if (choice === 'license') {
218
226
  console.log('');
219
- console.log(` 1. Visit ${chalk.cyan('https://nepopsx.dev/pricing')} to get a license`);
220
- console.log(` 2. Run ${chalk.cyan('nepopsx activate <key>')} to bind it`);
227
+ console.log(` 1. Visit ${chalk.cyan('https://nepopsx.dev/pricing')} to choose a plan`);
228
+ console.log(` 2. Run ${chalk.cyan('nepopsx login')} to connect this machine`);
221
229
  console.log(` 3. Re-run ${chalk.cyan('nepopsx init')} to configure your workspace\n`);
222
230
  return;
223
231
  }