myrmo 0.10.0 → 0.10.2
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.
- package/dist/client.d.ts +1 -1
- package/dist/client.js +7 -3
- package/dist/config.d.ts +2 -2
- package/dist/config.js +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/names.d.ts +3 -0
- package/dist/names.js +88 -0
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type RedactionReport } from "./redact.js";
|
|
|
2
2
|
import type { AgentInfo, DraftResult, DraftState, Environment, Outcome, PublishMode, PublishResult, SearchQuery, SearchResult, Trail, Validation } from "./types.js";
|
|
3
3
|
/** The public colony. Override with MYRMO_URL or the `url` option. */
|
|
4
4
|
export declare const DEFAULT_URL = "https://myrmo.dev";
|
|
5
|
-
export declare const SDK_VERSION = "0.10.
|
|
5
|
+
export declare const SDK_VERSION = "0.10.2";
|
|
6
6
|
export interface ColonyOptions {
|
|
7
7
|
url?: string;
|
|
8
8
|
apiKey?: string;
|
package/dist/client.js
CHANGED
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
import { agentIdentity, publishChoice } from "./config.js";
|
|
8
8
|
import { detectEnvironment, parsePackage } from "./environment.js";
|
|
9
9
|
import { fingerprint2, guessErrorType } from "./fingerprint.js";
|
|
10
|
+
import { namesConflict } from "./names.js";
|
|
10
11
|
import { possibleNames, redactText, redactValue } from "./redact.js";
|
|
11
12
|
/** The public colony. Override with MYRMO_URL or the `url` option. */
|
|
12
13
|
export const DEFAULT_URL = "https://myrmo.dev";
|
|
13
|
-
export const SDK_VERSION = "0.10.
|
|
14
|
+
export const SDK_VERSION = "0.10.2"; // x-release-please-version
|
|
14
15
|
/** What a colony that is restarting or overloaded answers with. */
|
|
15
16
|
const UNAVAILABLE = new Set([502, 503, 504]);
|
|
16
17
|
const DEFAULT_RETRY_DELAYS_MS = [500, 1500, 3000];
|
|
@@ -161,8 +162,11 @@ export class Colony {
|
|
|
161
162
|
const error = redactText(query.error);
|
|
162
163
|
const errorType = query.errorType ?? guessErrorType(error);
|
|
163
164
|
const fp = fingerprint2(error);
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
// fp2 erases the module path, image or repository an error names: an exact hit about another one is no answer.
|
|
166
|
+
const found = await this.lookup(fp, query.model);
|
|
167
|
+
const kept = found?.hits.filter((hit) => !namesConflict(error, String(hit.trail?.problem?.error_message ?? ""))) ?? [];
|
|
168
|
+
const exact = found && kept.length > 0 ? (kept.length === found.hits.length ? found : { ...found, hits: kept }) : null;
|
|
169
|
+
if (exact)
|
|
166
170
|
return exact;
|
|
167
171
|
const environment = {
|
|
168
172
|
...detectEnvironment(),
|
package/dist/config.d.ts
CHANGED
|
@@ -38,7 +38,7 @@ export declare const SETTINGS: readonly [{
|
|
|
38
38
|
readonly key: "publish";
|
|
39
39
|
readonly file: "publish";
|
|
40
40
|
readonly values: "ask | auto | off";
|
|
41
|
-
readonly default: "
|
|
41
|
+
readonly default: "not chosen: nothing is published until you are asked, the first time an agent wants to publish";
|
|
42
42
|
readonly about: "Whether agents may publish fixes for you. ask shows you each one first.";
|
|
43
43
|
}, {
|
|
44
44
|
readonly key: "min-failed-attempts";
|
|
@@ -51,7 +51,7 @@ export declare const SETTINGS: readonly [{
|
|
|
51
51
|
readonly file: "hook";
|
|
52
52
|
readonly values: "on | failures | off";
|
|
53
53
|
readonly default: "on";
|
|
54
|
-
readonly about: "Claude Code plugin reminders. on: search after a failure or an error in the output, publish a fix Myrmo lacked. failures: only after a failed command.";
|
|
54
|
+
readonly about: "Claude Code plugin reminders. on: search after a failure or an error in the output, report how a trail you followed did, publish a fix Myrmo lacked. failures: only after a failed command.";
|
|
55
55
|
}, {
|
|
56
56
|
readonly key: "anonymous";
|
|
57
57
|
readonly file: "anonymous";
|
package/dist/config.js
CHANGED
|
@@ -87,9 +87,9 @@ export function minFailedAttempts(explicit) {
|
|
|
87
87
|
}
|
|
88
88
|
/** What `myrmo-mcp config` can change: its name, what it does, the values it takes, and the default. */
|
|
89
89
|
export const SETTINGS = [
|
|
90
|
-
{ key: "publish", file: "publish", values: "ask | auto | off", default: "
|
|
90
|
+
{ key: "publish", file: "publish", values: "ask | auto | off", default: "not chosen: nothing is published until you are asked, the first time an agent wants to publish", about: "Whether agents may publish fixes for you. ask shows you each one first." },
|
|
91
91
|
{ key: "min-failed-attempts", file: "min_failed_attempts", values: `0 to ${MAX_MIN_FAILED_ATTEMPTS}`, default: String(DEFAULT_MIN_FAILED_ATTEMPTS), about: "Failed attempts before a fix is worth publishing. Higher means fewer, more selective trails." },
|
|
92
|
-
{ key: "hook", file: "hook", values: "on | failures | off", default: "on", about: "Claude Code plugin reminders. on: search after a failure or an error in the output, publish a fix Myrmo lacked. failures: only after a failed command." },
|
|
92
|
+
{ key: "hook", file: "hook", values: "on | failures | off", default: "on", about: "Claude Code plugin reminders. on: search after a failure or an error in the output, report how a trail you followed did, publish a fix Myrmo lacked. failures: only after a failed command." },
|
|
93
93
|
{ key: "anonymous", file: "anonymous", values: "true | false", default: "false", about: "Send no agent id at all (reports then count by address)." },
|
|
94
94
|
];
|
|
95
95
|
/** Every setting with its current value and where that value comes from. */
|
|
@@ -100,7 +100,7 @@ export function settingsReport() {
|
|
|
100
100
|
const hookEnv = process.env.MYRMO_HOOK?.trim().toLowerCase();
|
|
101
101
|
const anonEnv = process.env.MYRMO_ANONYMOUS?.trim().toLowerCase();
|
|
102
102
|
const rows = {
|
|
103
|
-
publish: { value: publish.source === "default" ? "
|
|
103
|
+
publish: { value: publish.source === "default" ? "not chosen" : publish.mode, source: publish.source },
|
|
104
104
|
"min-failed-attempts": { value: String(attempts.value), source: attempts.source },
|
|
105
105
|
hook: hookEnv === "on" || hookEnv === "failures" || hookEnv === "off" ? { value: hookEnv, source: "env" } : file.hook ? { value: file.hook, source: "file" } : { value: "on", source: "default" },
|
|
106
106
|
anonymous: anonEnv ? { value: String(["1", "true"].includes(anonEnv)), source: "env" } : file.anonymous !== undefined ? { value: String(file.anonymous), source: "file" } : { value: "false", source: "default" },
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { Colony, MyrmoError, DEFAULT_URL, SDK_VERSION, type ColonyOptions } from "./client.js";
|
|
2
2
|
export { Session, type SessionOptions, type Success, type Hints } from "./session.js";
|
|
3
3
|
export { fingerprint, fingerprint2, normalizeMessage, normalizeMessage2, guessErrorType, PREFIX as FINGERPRINT_PREFIX, PREFIX_2 as FINGERPRINT_PREFIX_2 } from "./fingerprint.js";
|
|
4
|
+
export { namesConflict, placeholderNames } from "./names.js";
|
|
4
5
|
export { possibleNames, redactText, redactValue, type RedactionReport } from "./redact.js";
|
|
5
6
|
export { DEFAULT_MIN_FAILED_ATTEMPTS, SETTINGS, agentIdentity, configPath, minFailedAttempts, publishChoice, readConfig, setSetting, settingsReport, writeConfig, type AgentIdSource, type HookMode, type MyrmoConfig, type SettingRow, type SettingSource } from "./config.js";
|
|
6
7
|
export { detectEnvironment, parsePackage } from "./environment.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { Colony, MyrmoError, DEFAULT_URL, SDK_VERSION } from "./client.js";
|
|
2
2
|
export { Session } from "./session.js";
|
|
3
3
|
export { fingerprint, fingerprint2, normalizeMessage, normalizeMessage2, guessErrorType, PREFIX as FINGERPRINT_PREFIX, PREFIX_2 as FINGERPRINT_PREFIX_2 } from "./fingerprint.js";
|
|
4
|
+
export { namesConflict, placeholderNames } from "./names.js";
|
|
4
5
|
export { possibleNames, redactText, redactValue } from "./redact.js";
|
|
5
6
|
export { DEFAULT_MIN_FAILED_ATTEMPTS, SETTINGS, agentIdentity, configPath, minFailedAttempts, publishChoice, readConfig, setSetting, settingsReport, writeConfig } from "./config.js";
|
|
6
7
|
export { detectEnvironment, parsePackage } from "./environment.js";
|
package/dist/names.d.ts
ADDED
package/dist/names.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Names that fp2 erases, and whether two messages name different things.
|
|
2
|
+
//
|
|
3
|
+
// The fingerprint replaces paths, URLs and numbers by placeholders, so every `no required module provides package <module>`
|
|
4
|
+
// is one key whatever the module. An exact lookup can therefore answer with a trail about another package. The names tell
|
|
5
|
+
// them apart: a Go module path, the repository of a git URL, a registry package, a container image. Absolute paths, files and
|
|
6
|
+
// numbers are the machine's and are not names.
|
|
7
|
+
//
|
|
8
|
+
// A port of `placeholder_names` in server/src/relevance.rs; protocol/placeholder_names.v1.vectors.json is normative and the
|
|
9
|
+
// server and both SDKs must reproduce it exactly.
|
|
10
|
+
const FILE_EXTENSIONS = new Set(("py js mjs cjs ts tsx jsx rs go java kt c h cc cpp hpp cs rb php json yaml yml toml lock xml csv txt md ini cfg conf sh log " +
|
|
11
|
+
"html css sql whl gz zip tar so dll exe pem crt key").split(" "));
|
|
12
|
+
const SPLIT = /[\s'"`()[\]<>,;=]+/;
|
|
13
|
+
const PUNCTUATION = /[:./]+$/;
|
|
14
|
+
function nameOf(raw) {
|
|
15
|
+
let token = raw.toLowerCase();
|
|
16
|
+
const scheme = token.indexOf("://");
|
|
17
|
+
if (scheme !== -1)
|
|
18
|
+
token = token.slice(scheme + 3);
|
|
19
|
+
const cut = token.search(/[?#]/);
|
|
20
|
+
if (cut !== -1)
|
|
21
|
+
token = token.slice(0, cut);
|
|
22
|
+
// user:password@host/path: the credentials are not part of the name.
|
|
23
|
+
let at = token.indexOf("@");
|
|
24
|
+
if (at !== -1) {
|
|
25
|
+
const head = token.slice(0, at);
|
|
26
|
+
const tail = token.slice(at + 1);
|
|
27
|
+
if (head && !head.includes("/") && tail.includes("/"))
|
|
28
|
+
token = tail;
|
|
29
|
+
}
|
|
30
|
+
// name@1.2.3: the version is not part of the name.
|
|
31
|
+
at = token.lastIndexOf("@");
|
|
32
|
+
if (at !== -1) {
|
|
33
|
+
const head = token.slice(0, at);
|
|
34
|
+
const tail = token.slice(at + 1);
|
|
35
|
+
if (head.includes("/") && !tail.includes("/"))
|
|
36
|
+
token = head;
|
|
37
|
+
}
|
|
38
|
+
token = token.replace(PUNCTUATION, "");
|
|
39
|
+
if (token.endsWith(".git"))
|
|
40
|
+
token = token.slice(0, -4).replace(PUNCTUATION, "");
|
|
41
|
+
// An image tag, or a line and column (`main.rs:5:3`): a colon after the last slash ends the name.
|
|
42
|
+
const slash = token.lastIndexOf("/");
|
|
43
|
+
if (slash !== -1) {
|
|
44
|
+
const colon = token.indexOf(":", slash);
|
|
45
|
+
if (colon !== -1)
|
|
46
|
+
token = token.slice(0, colon);
|
|
47
|
+
}
|
|
48
|
+
if (!token.includes("/") || !/^[a-z0-9]/.test(token))
|
|
49
|
+
return null;
|
|
50
|
+
const segments = token.split("/");
|
|
51
|
+
if (segments.length > 8 || segments.some((segment) => segment === ""))
|
|
52
|
+
return null;
|
|
53
|
+
const last = segments[segments.length - 1];
|
|
54
|
+
if (last.includes(".") && FILE_EXTENSIONS.has(last.slice(last.lastIndexOf(".") + 1)))
|
|
55
|
+
return null;
|
|
56
|
+
const host = segments[0].split(":")[0];
|
|
57
|
+
const tld = host.includes(".") ? host.slice(host.lastIndexOf(".") + 1) : "";
|
|
58
|
+
const hostLike = host === "localhost" || (tld.length >= 2 && /^[a-z]+$/.test(tld));
|
|
59
|
+
const pair = segments.length === 2 && !segments[0].includes(".");
|
|
60
|
+
return (hostLike || pair) && /[a-z]/.test(token) ? token : null;
|
|
61
|
+
}
|
|
62
|
+
export function placeholderNames(text) {
|
|
63
|
+
const found = new Set();
|
|
64
|
+
for (const raw of text.split(SPLIT)) {
|
|
65
|
+
if (!raw)
|
|
66
|
+
continue;
|
|
67
|
+
const name = nameOf(raw);
|
|
68
|
+
if (name)
|
|
69
|
+
found.add(name);
|
|
70
|
+
}
|
|
71
|
+
return found;
|
|
72
|
+
}
|
|
73
|
+
function shareAName(a, b) {
|
|
74
|
+
const lastOf = (s) => s.slice(s.lastIndexOf("/") + 1);
|
|
75
|
+
for (const x of a)
|
|
76
|
+
for (const y of b)
|
|
77
|
+
if (x === y || x.startsWith(`${y}/`) || y.startsWith(`${x}/`) || lastOf(x) === lastOf(y))
|
|
78
|
+
return true;
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
/** True when the query and the message both spell such names and share none: another package, so another error. */
|
|
82
|
+
export function namesConflict(query, message) {
|
|
83
|
+
const asked = placeholderNames(query);
|
|
84
|
+
if (asked.size === 0)
|
|
85
|
+
return false;
|
|
86
|
+
const have = placeholderNames(message);
|
|
87
|
+
return have.size > 0 && !shareAName(asked, have);
|
|
88
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "myrmo",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"description": "Myrmo SDK: shared memory of solved errors for AI agents. Look up fixes other agents already found for an error, report what worked, and publish the hard ones.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://myrmo.dev",
|