premanmcp 0.10.3 → 0.10.4

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 (2) hide show
  1. package/bin/connect.js +36 -24
  2. package/package.json +1 -1
package/bin/connect.js CHANGED
@@ -1130,7 +1130,7 @@ export function headlessDiscovery(agent, serverName, instructions = []) {
1130
1130
  *
1131
1131
  * Never throws: a failed discovery must not fail the connect.
1132
1132
  */
1133
- async function discoverEndpoints(args, agent, serverName) {
1133
+ async function discoverEndpoints(args, agent, serverName, blockedHere = "") {
1134
1134
  try {
1135
1135
  const before = await endpointCounts(args);
1136
1136
  if (before.registered) {
@@ -1142,7 +1142,10 @@ async function discoverEndpoints(args, agent, serverName) {
1142
1142
 
1143
1143
  const brief = await callPremanTool(args, "discover_endpoints_from_codebase", { base_path: "." });
1144
1144
  const spec = headlessDiscovery(agent, serverName, brief.instructions || []);
1145
- const blocker = spec && onPath(spec.bin) ? agentBlocker(agent.id) : "";
1145
+ // Discovery has to read *this* repo, so it cannot be moved out of a directory
1146
+ // that redirects it the way the check-in was — it can only be skipped, before
1147
+ // it spends ten minutes proving what the self-test already found out.
1148
+ const blocker = blockedHere || (spec && onPath(spec.bin) ? agentBlocker(agent.id) : "");
1146
1149
  if (!spec || !onPath(spec.bin) || blocker) {
1147
1150
  // Say why before printing homework: "here is a brief" reads as PreMan not
1148
1151
  // working, when the actual answer is one login away.
@@ -1442,11 +1445,11 @@ async function setUpPushTesting(args) {
1442
1445
  * Order follows what a new account needs to see: what PreMan found, then where to
1443
1446
  * watch it, then who to tell, then when to run it.
1444
1447
  */
1445
- async function guidedFirstRun(args, agent, apiKey, serverName) {
1448
+ async function guidedFirstRun(args, agent, apiKey, serverName, { blockedHere = "" } = {}) {
1446
1449
  const assumeYes = args.has("--yes");
1447
1450
 
1448
1451
  step("Endpoints");
1449
- const counts = await discoverEndpoints(args, agent, serverName);
1452
+ const counts = await discoverEndpoints(args, agent, serverName, blockedHere);
1450
1453
 
1451
1454
  if (counts.first) {
1452
1455
  step("First test");
@@ -1661,14 +1664,13 @@ export async function connectCommand(commandArgs) {
1661
1664
  return;
1662
1665
  }
1663
1666
 
1664
- if (
1665
- !(await establishCheckIn(args, agent, apiKey, {
1666
- serverName,
1667
- written,
1668
- serverConfig,
1669
- projectInstall,
1670
- }))
1671
- ) {
1667
+ const checkIn = await establishCheckIn(args, agent, apiKey, {
1668
+ serverName,
1669
+ written,
1670
+ serverConfig,
1671
+ projectInstall,
1672
+ });
1673
+ if (!checkIn.linked) {
1672
1674
  // Still honour an explicitly-passed credential, but do not open a new prompt
1673
1675
  // on top of a connect that just told the user something went wrong.
1674
1676
  await captureDispatchCredential(args, agent, apiKey, { prompt: false });
@@ -1677,7 +1679,7 @@ export async function connectCommand(commandArgs) {
1677
1679
 
1678
1680
  process.stdout.write(`${MARK.ok()} Connected as ${agent.label}.\n`);
1679
1681
  if (!args.has("--no-guide")) {
1680
- await guidedFirstRun(args, agent, apiKey, serverName);
1682
+ await guidedFirstRun(args, agent, apiKey, serverName, { blockedHere: checkIn.blockedHere });
1681
1683
  }
1682
1684
  await captureDispatchCredential(args, agent, apiKey);
1683
1685
  }
@@ -1744,8 +1746,10 @@ export function neutralCwd(candidates = [os.homedir(), os.tmpdir()]) {
1744
1746
  * end: the steps below are measured in minutes, and a note that explains what is
1745
1747
  * happening is worth nothing after it has stopped happening.
1746
1748
  *
1747
- * Returns whether the check-in landed, and prints the troubleshooting block
1748
- * itself when it did not.
1749
+ * Returns whether the check-in landed and, when this directory redirects it, why
1750
+ * nothing started here can use PreMan — the caller has its own agent to run once
1751
+ * this is done. Prints the troubleshooting block itself when the link did not
1752
+ * land.
1749
1753
  */
1750
1754
  async function establishCheckIn(
1751
1755
  args,
@@ -1754,9 +1758,11 @@ async function establishCheckIn(
1754
1758
  { serverName, written, serverConfig, projectInstall = false }
1755
1759
  ) {
1756
1760
  const notes = [];
1757
- // Set only when this directory would redirect the agent, and then it is where
1758
- // the agent gets started instead.
1761
+ // Both set only when this directory redirects the agent: where it can be
1762
+ // started instead, and why an agent left standing here cannot use PreMan at all.
1759
1763
  let elsewhere = null;
1764
+ let blockedHere = "";
1765
+ const done = (linked) => ({ linked, blockedHere });
1760
1766
  const ticker = pollTicker();
1761
1767
  const say = (text) => {
1762
1768
  ticker.end();
@@ -1781,7 +1787,7 @@ async function establishCheckIn(
1781
1787
  );
1782
1788
  }
1783
1789
  if (test.ok && status.authenticated && (await waitForConnection(args, apiKey, { timeoutMs: 15000 }))) {
1784
- return true;
1790
+ return done(true);
1785
1791
  }
1786
1792
  note(
1787
1793
  test.ok
@@ -1806,6 +1812,12 @@ async function establishCheckIn(
1806
1812
  `directory forces: ${cliInvocation()} connect ${flag} --backend ${redirect.actual} ` +
1807
1813
  `(needs a key issued by it, and that API running).`
1808
1814
  );
1815
+ // Linking is not the only thing this directory breaks: whatever runs here
1816
+ // next gets the same redirected, unauthenticated server, and the callers
1817
+ // that would start an agent in it need to hear so.
1818
+ blockedHere =
1819
+ `${redirect.path} sends ${agent.label} to ${redirect.actual} in this directory, ` +
1820
+ `where this key is not valid.`;
1809
1821
 
1810
1822
  // The config we wrote is correct; the directory around it is not. Since the
1811
1823
  // server only reads the file it is standing in, everything this does next
@@ -1813,7 +1825,7 @@ async function establishCheckIn(
1813
1825
  const outside = neutralCwd();
1814
1826
  if (!outside) {
1815
1827
  notLinked(`Run '${cliInvocation()} connect' from your own project instead of this directory.`);
1816
- return false;
1828
+ return done(false);
1817
1829
  }
1818
1830
 
1819
1831
  say(
@@ -1834,7 +1846,7 @@ async function establishCheckIn(
1834
1846
  retry.status?.authenticated &&
1835
1847
  (await waitForConnection(args, apiKey, { timeoutMs: 15000 }))
1836
1848
  ) {
1837
- return true;
1849
+ return done(true);
1838
1850
  }
1839
1851
 
1840
1852
  if (projectInstall) {
@@ -1845,7 +1857,7 @@ async function establishCheckIn(
1845
1857
  `This --project config exists only here; started anywhere else, ` +
1846
1858
  `${agent.label} has no ${serverName} server to call.`
1847
1859
  );
1848
- return false;
1860
+ return done(false);
1849
1861
  }
1850
1862
  elsewhere = outside;
1851
1863
  }
@@ -1867,7 +1879,7 @@ async function establishCheckIn(
1867
1879
  });
1868
1880
  if (launch.connected) {
1869
1881
  ticker.end();
1870
- return true;
1882
+ return done(true);
1871
1883
  }
1872
1884
  if (launch.ran && !launch.interactive) {
1873
1885
  const why = lastLine(launch.output);
@@ -1896,7 +1908,7 @@ async function establishCheckIn(
1896
1908
 
1897
1909
  if (await waitForConnection(args, apiKey, { onPoll: ticker.tick })) {
1898
1910
  ticker.end();
1899
- return true;
1911
+ return done(true);
1900
1912
  }
1901
1913
 
1902
1914
  say(
@@ -1907,5 +1919,5 @@ async function establishCheckIn(
1907
1919
  ` - Then ask ${agent.label} to "run preman_status" — it links on its first PreMan call.\n` +
1908
1920
  ` - Then: ${cliInvocation()} connect --agent ${agent.id.replace("_", "-")}\n`
1909
1921
  );
1910
- return false;
1922
+ return done(false);
1911
1923
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "premanmcp",
3
- "version": "0.10.3",
3
+ "version": "0.10.4",
4
4
  "description": "Turn APIs into agent-callable MCP tools with auth, testing, and audit logs",
5
5
  "type": "module",
6
6
  "bin": {