@mocito/pi-goal 0.1.0 → 0.1.1
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/CHANGELOG.md +4 -0
- package/README.md +11 -2
- package/SECURITY.md +3 -1
- package/extensions/pi-goal/index.ts +3 -0
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/install-telemetry.ts +104 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.1
|
|
4
|
+
|
|
5
|
+
- Add best-effort install/update telemetry, gated by Pi telemetry/offline settings and disabled in CI.
|
|
6
|
+
|
|
3
7
|
## 0.1.0
|
|
4
8
|
|
|
5
9
|
- Initial `@mocito/pi-goal` package with `/goal`, goal tools, branch-scoped session persistence, usage accounting, UI status, and automatic continuation.
|
package/README.md
CHANGED
|
@@ -69,7 +69,14 @@ Branch behavior: goal mutations are stored on the current session branch. If you
|
|
|
69
69
|
|
|
70
70
|
## Configuration
|
|
71
71
|
|
|
72
|
-
v1 has no user-facing configuration. Automatic continuation is enabled for active goals and stops when the goal is paused, blocked, complete, usage-limited, budget-limited, cleared, or when pending user messages exist.
|
|
72
|
+
v1 has no user-facing goal configuration. Automatic continuation is enabled for active goals and stops when the goal is paused, blocked, complete, usage-limited, budget-limited, cleared, or when pending user messages exist.
|
|
73
|
+
|
|
74
|
+
Environment flags:
|
|
75
|
+
|
|
76
|
+
| Flag | Description |
|
|
77
|
+
| --- | --- |
|
|
78
|
+
| `PI_OFFLINE=1` | Disables install/update telemetry. |
|
|
79
|
+
| `PI_TELEMETRY=0` | Disables install/update telemetry. |
|
|
73
80
|
|
|
74
81
|
## Troubleshooting
|
|
75
82
|
|
|
@@ -120,4 +127,6 @@ Use the project-local release command from the repository root when possible:
|
|
|
120
127
|
|
|
121
128
|
Pi packages execute arbitrary code with your user permissions. Install only from sources you trust.
|
|
122
129
|
|
|
123
|
-
`pi-goal` does not require API keys
|
|
130
|
+
`pi-goal` does not require API keys and does not read provider credentials. Goal state is stored in local Pi session entries and goal objectives may be sent to the active model as hidden continuation context. Do not put secrets, credentials, tokens, or private data into goal objectives.
|
|
131
|
+
|
|
132
|
+
On startup, Pi Goal sends a best-effort install/update telemetry ping once per package version unless Pi telemetry is disabled, offline mode is enabled, or Pi runs in CI. See [SECURITY.md](./SECURITY.md) for the full security model and reporting instructions.
|
package/SECURITY.md
CHANGED
|
@@ -23,6 +23,8 @@ The maintainer will acknowledge reports as soon as practical and coordinate disc
|
|
|
23
23
|
|
|
24
24
|
`pi-goal` stores goal state as custom entries in the current Pi session branch. Goal objectives and usage summaries may appear in local Pi session files and in hidden continuation context sent to the active model. Do not put secrets, credentials, tokens, or private data into goal objectives.
|
|
25
25
|
|
|
26
|
-
The package does not require API keys
|
|
26
|
+
The package does not require API keys and does not read provider credentials. Its model tools can only inspect the current goal, create a new explicitly requested goal when none exists, or mark the current goal `complete`/`blocked`.
|
|
27
|
+
|
|
28
|
+
On startup, the extension sends a best-effort install/update telemetry ping to `mocito.dev` once per package version unless Pi telemetry is disabled, offline mode is enabled, or Pi runs in CI. The ping includes only the package name, version, and parsed platform/runtime/architecture from its User-Agent; it does not include prompts, goal objectives, file paths, session data, config values, or API keys. Telemetry writes a local deduplication marker under Pi's agent extensions directory.
|
|
27
29
|
|
|
28
30
|
Goal objectives are treated as untrusted user-provided task data when continuation context is built. They are JSON-encoded before being embedded in the hidden context message to reduce prompt-injection risk from delimiter-breaking text.
|
|
@@ -4,6 +4,7 @@ import { goalCompletions, handleGoalCommand } from "../../src/commands.js";
|
|
|
4
4
|
import { filterGoalContextMessages, GoalContinuationScheduler } from "../../src/continuation.js";
|
|
5
5
|
import { registerGoalRenderers } from "../../src/rendering.js";
|
|
6
6
|
import { appendGoalMutation, applyGoalMutation, reconstructGoalState, statusMutation } from "../../src/state.js";
|
|
7
|
+
import { reportInstallTelemetry } from "../../src/install-telemetry.js";
|
|
7
8
|
import { registerGoalTools } from "../../src/tools.js";
|
|
8
9
|
import type { GoalState } from "../../src/types.js";
|
|
9
10
|
import { GOAL_EVENT_TYPE } from "../../src/types.js";
|
|
@@ -11,6 +12,8 @@ import { nowIso, realizedTimeUsed } from "../../src/utils.js";
|
|
|
11
12
|
import { clearGoalUi, updateGoalUi } from "../../src/ui.js";
|
|
12
13
|
|
|
13
14
|
export default function piGoal(pi: ExtensionAPI) {
|
|
15
|
+
reportInstallTelemetry();
|
|
16
|
+
|
|
14
17
|
let goal: GoalState | null = null;
|
|
15
18
|
const scheduler = new GoalContinuationScheduler(pi, { getGoal: () => goal });
|
|
16
19
|
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
6
|
+
|
|
7
|
+
const PACKAGE_NAME = "pi-goal";
|
|
8
|
+
const INSTALL_TELEMETRY_URL = "https://mocito.dev/api/report-install";
|
|
9
|
+
const INSTALL_TELEMETRY_TIMEOUT_MS = 5000;
|
|
10
|
+
const CI_ENVIRONMENT_VARIABLES = [
|
|
11
|
+
"APPVEYOR",
|
|
12
|
+
"BITBUCKET_BUILD_NUMBER",
|
|
13
|
+
"BUILDKITE",
|
|
14
|
+
"CIRCLECI",
|
|
15
|
+
"CODESPACES",
|
|
16
|
+
"DRONE",
|
|
17
|
+
"GITHUB_ACTIONS",
|
|
18
|
+
"GITLAB_CI",
|
|
19
|
+
"JENKINS_URL",
|
|
20
|
+
"NETLIFY",
|
|
21
|
+
"TEAMCITY_VERSION",
|
|
22
|
+
"TF_BUILD",
|
|
23
|
+
"TRAVIS",
|
|
24
|
+
"VERCEL",
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
interface InstallTelemetryState {
|
|
28
|
+
lastReportedVersion?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface PiSettingsDocument {
|
|
32
|
+
enableInstallTelemetry?: unknown;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function readJsonFile(path: string): unknown {
|
|
36
|
+
try {
|
|
37
|
+
return JSON.parse(readFileSync(path, "utf8")) as unknown;
|
|
38
|
+
} catch {
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isTruthyEnvFlag(value: string | undefined): boolean {
|
|
44
|
+
if (!value) return false;
|
|
45
|
+
return value === "1" || value.toLowerCase() === "true" || value.toLowerCase() === "yes";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function isPresentEnvFlag(value: string | undefined): boolean {
|
|
49
|
+
if (!value) return false;
|
|
50
|
+
const normalized = value.toLowerCase();
|
|
51
|
+
return normalized !== "0" && normalized !== "false" && normalized !== "no";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isCiEnvironment(): boolean {
|
|
55
|
+
if (isTruthyEnvFlag(process.env.CI)) return true;
|
|
56
|
+
return CI_ENVIRONMENT_VARIABLES.some((name) => isPresentEnvFlag(process.env[name]));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function isInstallTelemetryEnabled(): boolean {
|
|
60
|
+
if (isCiEnvironment()) return false;
|
|
61
|
+
if (isTruthyEnvFlag(process.env.PI_OFFLINE)) return false;
|
|
62
|
+
if (process.env.PI_TELEMETRY !== undefined) return isTruthyEnvFlag(process.env.PI_TELEMETRY);
|
|
63
|
+
|
|
64
|
+
const settings = readJsonFile(join(getAgentDir(), "settings.json")) as PiSettingsDocument;
|
|
65
|
+
return settings.enableInstallTelemetry !== false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function getPackageVersion(): string {
|
|
69
|
+
const packageJson = readJsonFile(fileURLToPath(new URL("../package.json", import.meta.url))) as { version?: unknown };
|
|
70
|
+
return typeof packageJson.version === "string" && packageJson.version.length > 0 ? packageJson.version : "0.0.0";
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function getInstallTelemetryUserAgent(version: string): string {
|
|
74
|
+
const runtimeVersions = process.versions as NodeJS.ProcessVersions & { bun?: string };
|
|
75
|
+
const runtime = runtimeVersions.bun ? `bun/${runtimeVersions.bun}` : `node/${process.version}`;
|
|
76
|
+
return `${PACKAGE_NAME}/${version} (${process.platform}; ${runtime}; ${process.arch})`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function reportInstallTelemetryAsync(): Promise<void> {
|
|
80
|
+
try {
|
|
81
|
+
if (!isInstallTelemetryEnabled()) return;
|
|
82
|
+
|
|
83
|
+
const version = getPackageVersion();
|
|
84
|
+
const extensionsDir = join(getAgentDir(), "extensions");
|
|
85
|
+
const statePath = join(extensionsDir, "pi-goal-install.json");
|
|
86
|
+
const state = readJsonFile(statePath) as InstallTelemetryState;
|
|
87
|
+
if (state.lastReportedVersion === version) return;
|
|
88
|
+
|
|
89
|
+
await mkdir(extensionsDir, { recursive: true });
|
|
90
|
+
await writeFile(statePath, `${JSON.stringify({ lastReportedVersion: version }, null, 2)}\n`, "utf8");
|
|
91
|
+
|
|
92
|
+
const params = new URLSearchParams({ tool: PACKAGE_NAME, version });
|
|
93
|
+
await fetch(`${INSTALL_TELEMETRY_URL}?${params.toString()}`, {
|
|
94
|
+
headers: { "User-Agent": getInstallTelemetryUserAgent(version) },
|
|
95
|
+
signal: AbortSignal.timeout(INSTALL_TELEMETRY_TIMEOUT_MS),
|
|
96
|
+
});
|
|
97
|
+
} catch {
|
|
98
|
+
// Best-effort telemetry: ignore settings, filesystem, and network failures.
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function reportInstallTelemetry(): void {
|
|
103
|
+
void reportInstallTelemetryAsync();
|
|
104
|
+
}
|