pi-harness-runtime 1.1.403 → 1.1.405
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 +7 -0
- package/index.ts +275 -1
- package/package.json +1 -1
- package/packages/a2a-adapter/package.json +1 -1
- package/packages/agent-policy/package.json +1 -1
- package/packages/architecture-generator/package.json +1 -1
- package/packages/auth/package.json +1 -1
- package/packages/autonomous-refactor/package.json +1 -1
- package/packages/autonomous-runtime/package.json +1 -1
- package/packages/cache-strategy/package.json +1 -1
- package/packages/capability-registry/package.json +1 -1
- package/packages/checkpoint/package.json +1 -1
- package/packages/cli-plugin-sdk/package.json +1 -1
- package/packages/clipboard/package.json +1 -1
- package/packages/clipboard-plugin/package.json +1 -1
- package/packages/code-generation/package.json +1 -1
- package/packages/code-review/package.json +1 -1
- package/packages/codex-adapter/package.json +1 -1
- package/packages/codex-watcher/package.json +1 -1
- package/packages/config-capture/package.json +1 -1
- package/packages/connection-runtime/package.json +1 -1
- package/packages/context-compiler/package.json +1 -1
- package/packages/context-discovery/package.json +1 -1
- package/packages/context-manager/package.json +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/cookie-sanitizer/package.json +1 -1
- package/packages/cost-optimizer/package.json +1 -1
- package/packages/dependency-analyzer/package.json +1 -1
- package/packages/django-plugin/package.json +1 -1
- package/packages/doc-generator/package.json +1 -1
- package/packages/durable-review/package.json +1 -1
- package/packages/e2e-tester/package.json +1 -1
- package/packages/evaluation-engine/package.json +1 -1
- package/packages/evaluation-runner/package.json +1 -1
- package/packages/event-bus/package.json +1 -1
- package/packages/event-sink/package.json +1 -1
- package/packages/event-store/package.json +1 -1
- package/packages/experience-replay/package.json +1 -1
- package/packages/feedback-collector/package.json +1 -1
- package/packages/file-copy-helper/package.json +1 -1
- package/packages/framework-detector/package.json +1 -1
- package/packages/framework-plugin-sdk/package.json +1 -1
- package/packages/frappe-plugin/package.json +1 -1
- package/packages/generic-web-plugin/package.json +1 -1
- package/packages/health-monitor/package.json +1 -1
- package/packages/intent-analyzer/package.json +1 -1
- package/packages/jev-judge/dist/auto-continue.d.ts +6 -0
- package/packages/jev-judge/dist/auto-continue.d.ts.map +1 -1
- package/packages/jev-judge/dist/auto-continue.js +13 -3
- package/packages/jev-judge/dist/auto-continue.js.map +1 -1
- package/packages/jev-judge/package.json +1 -1
- package/packages/jev-judge/src/auto-continue.ts +17 -3
- package/packages/jev-judge/tests/auto-continue-context.test.ts +37 -0
- package/packages/knowledge-graph/package.json +1 -1
- package/packages/knowledge-retrieval/package.json +1 -1
- package/packages/laravel-plugin/package.json +1 -1
- package/packages/learning-engine/package.json +1 -1
- package/packages/logging/package.json +1 -1
- package/packages/mcp-adapter/package.json +1 -1
- package/packages/memory-engine/package.json +1 -1
- package/packages/milestone-manager/package.json +1 -1
- package/packages/model-registry/package.json +1 -1
- package/packages/nextjs-plugin/package.json +1 -1
- package/packages/notification/dist/adapters/line-adapter.d.ts.map +1 -1
- package/packages/notification/dist/adapters/line-adapter.js +6 -1
- package/packages/notification/dist/adapters/line-adapter.js.map +1 -1
- package/packages/notification/dist/notification-center.d.ts.map +1 -1
- package/packages/notification/dist/notification-center.js +32 -0
- package/packages/notification/dist/notification-center.js.map +1 -1
- package/packages/notification/dist/telegram-webhook-handler.d.ts +7 -0
- package/packages/notification/dist/telegram-webhook-handler.d.ts.map +1 -1
- package/packages/notification/dist/telegram-webhook-handler.js +7 -0
- package/packages/notification/dist/telegram-webhook-handler.js.map +1 -1
- package/packages/notification/dist/types.d.ts +1 -1
- package/packages/notification/dist/types.d.ts.map +1 -1
- package/packages/notification/package.json +1 -1
- package/packages/notification/src/adapters/line-adapter.ts +7 -1
- package/packages/notification/src/notification-center.ts +30 -0
- package/packages/notification/src/telegram-webhook-handler.ts +7 -0
- package/packages/notification/src/types.ts +1 -0
- package/packages/notification/test/notification.test.ts +31 -28
- package/packages/notification/test/tooling-proposal-payload.test.ts +212 -0
- package/packages/observability/package.json +1 -1
- package/packages/okf-indexer/package.json +1 -1
- package/packages/paperclip-integration/package.json +1 -1
- package/packages/performance-optimizer/package.json +1 -1
- package/packages/permission-mode/package.json +1 -1
- package/packages/privilege-broker/package.json +1 -1
- package/packages/project-analyzer/package.json +1 -1
- package/packages/project-bootstrap/package.json +1 -1
- package/packages/projection-engine/package.json +1 -1
- package/packages/prompt-compiler/package.json +1 -1
- package/packages/prompt-versioning/package.json +1 -1
- package/packages/provider-adapter-sdk/package.json +1 -1
- package/packages/provider-router/package.json +1 -1
- package/packages/provider-selector/package.json +1 -1
- package/packages/providers/package.json +1 -1
- package/packages/qdrant-skills/package.json +1 -1
- package/packages/quota-manager/package.json +1 -1
- package/packages/rate-limiter/package.json +1 -1
- package/packages/react-vite-plugin/package.json +1 -1
- package/packages/relay/package.json +1 -1
- package/packages/release-manager/package.json +1 -1
- package/packages/requirement-compiler/package.json +1 -1
- package/packages/runtime/package.json +1 -1
- package/packages/scheduler/package.json +1 -1
- package/packages/scheduler-adapter/package.json +1 -1
- package/packages/session/package.json +1 -1
- package/packages/session-api/package.json +1 -1
- package/packages/session-export/package.json +1 -1
- package/packages/shared-context/package.json +1 -1
- package/packages/skill-mcp-client/package.json +1 -1
- package/packages/skill-registry/package.json +1 -1
- package/packages/skills/package.json +1 -1
- package/packages/sprint-planner/package.json +1 -1
- package/packages/subscription-engine/package.json +1 -1
- package/packages/task-compiler/package.json +1 -1
- package/packages/telegram/package.json +1 -1
- package/packages/tencentdb-memory/package.json +1 -1
- package/packages/tencentdb-sync/package.json +1 -1
- package/packages/test-data-generator/package.json +1 -1
- package/packages/test-generator/package.json +1 -1
- package/packages/todo-bd-sync/package.json +1 -1
- package/packages/token-estimation/package.json +1 -1
- package/packages/token-optimizer/package.json +1 -1
- package/packages/tooling-preference/dist/detect.d.ts +62 -0
- package/packages/tooling-preference/dist/detect.d.ts.map +1 -0
- package/packages/tooling-preference/dist/detect.js +209 -0
- package/packages/tooling-preference/dist/detect.js.map +1 -0
- package/packages/tooling-preference/dist/index.d.ts +13 -0
- package/packages/tooling-preference/dist/index.d.ts.map +1 -0
- package/packages/tooling-preference/dist/index.js +13 -0
- package/packages/tooling-preference/dist/index.js.map +1 -0
- package/packages/tooling-preference/dist/proposal.d.ts +70 -0
- package/packages/tooling-preference/dist/proposal.d.ts.map +1 -0
- package/packages/tooling-preference/dist/proposal.js +137 -0
- package/packages/tooling-preference/dist/proposal.js.map +1 -0
- package/packages/tooling-preference/dist/registry.d.ts +50 -0
- package/packages/tooling-preference/dist/registry.d.ts.map +1 -0
- package/packages/tooling-preference/dist/registry.js +53 -0
- package/packages/tooling-preference/dist/registry.js.map +1 -0
- package/packages/tooling-preference/dist/store.d.ts +61 -0
- package/packages/tooling-preference/dist/store.d.ts.map +1 -0
- package/packages/tooling-preference/dist/store.js +129 -0
- package/packages/tooling-preference/dist/store.js.map +1 -0
- package/packages/tooling-preference/package.json +21 -0
- package/packages/tooling-preference/src/detect.ts +251 -0
- package/packages/tooling-preference/src/index.ts +44 -0
- package/packages/tooling-preference/src/proposal.ts +173 -0
- package/packages/tooling-preference/src/registry.ts +79 -0
- package/packages/tooling-preference/src/store.ts +162 -0
- package/packages/tooling-preference/tests/detect.test.ts +188 -0
- package/packages/tooling-preference/tests/proposal.test.ts +107 -0
- package/packages/tooling-preference/tests/registry.test.ts +51 -0
- package/packages/tooling-preference/tests/store.test.ts +99 -0
- package/packages/trajectory/package.json +1 -1
- package/packages/tui/package.json +1 -1
- package/packages/types/package.json +1 -1
- package/packages/voice-api/package.json +1 -1
- package/packages/webmcp-tester/package.json +1 -1
- package/packages/wiki/package.json +1 -1
- package/packages/workflow-events/package.json +1 -1
- package/packages/workspace-scanner/package.json +1 -1
- package/packages/worktree/package.json +1 -1
- package/packages/write-review/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACN,oBAAoB,EACpB,oBAAoB,EACpB,gCAAgC,EAChC,KAAK,mBAAmB,EACxB,KAAK,cAAc,GACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EACN,mBAAmB,EACnB,gCAAgC,EAChC,2BAA2B,EAC3B,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,aAAa,GAClB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACN,iBAAiB,EACjB,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,KAAK,uBAAuB,GAC5B,MAAM,YAAY,CAAC;AAEpB,OAAO,EACN,sBAAsB,EACtB,KAAK,cAAc,EACnB,KAAK,iBAAiB,GACtB,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The JS/TS tooling preference of a workspace.
|
|
3
|
+
*
|
|
4
|
+
* The harness offers the user to replace ESLint and Prettier with Biome.js
|
|
5
|
+
* in a JavaScript/TypeScript workspace. The offer is a decision of its own:
|
|
6
|
+
* it never pauses the work and never travels through the task-approval
|
|
7
|
+
* path.
|
|
8
|
+
*/
|
|
9
|
+
export { detectPackageManager, detectToolingContext, evaluateBiomeProposalEligibility, } from "./detect.js";
|
|
10
|
+
export { buildToolingButtons, buildToolingImplementationPrompt, buildToolingProposalMessage, buildToolingRequestId, buildToolingUserKey, parseToolingTarget, TOOLING_ACTION, } from "./proposal.js";
|
|
11
|
+
export { harnessRuntimeDir, shouldAskAgain, ToolingPreferenceStore, toolingPreferenceKey, } from "./store.js";
|
|
12
|
+
export { ToolingRequestRegistry, } from "./registry.js";
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACN,oBAAoB,EACpB,oBAAoB,EACpB,gCAAgC,GAGhC,MAAM,aAAa,CAAC;AAErB,OAAO,EACN,mBAAmB,EACnB,gCAAgC,EAChC,2BAA2B,EAC3B,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,GAKd,MAAM,eAAe,CAAC;AAEvB,OAAO,EACN,iBAAiB,EACjB,cAAc,EACd,sBAAsB,EACtB,oBAAoB,GAEpB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACN,sBAAsB,GAGtB,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tooling proposal: request IDs, buttons and the wording.
|
|
3
|
+
*
|
|
4
|
+
* The proposal is a decision of its own. It never travels through the
|
|
5
|
+
* task-approval path, because a "No" there pauses the work and a "Yes"
|
|
6
|
+
* there resumes it - neither belongs to a tooling preference.
|
|
7
|
+
*/
|
|
8
|
+
import type { ToolingContext } from "./detect.js";
|
|
9
|
+
/**
|
|
10
|
+
* The callback action of the proposal.
|
|
11
|
+
*
|
|
12
|
+
* The callback data is parsed by splitting on "_", so an action must be a
|
|
13
|
+
* single token: an action that carries an underscore would be read as the
|
|
14
|
+
* action up to that underscore, and the rest as the target.
|
|
15
|
+
*/
|
|
16
|
+
export declare const TOOLING_ACTION = "biome";
|
|
17
|
+
/** The answer of the user. */
|
|
18
|
+
export type ToolingChoice = "yes" | "no";
|
|
19
|
+
/** The saved preference of a user in a workspace. */
|
|
20
|
+
export type ToolingPreference = "prefer_biome" | "use_project_tools";
|
|
21
|
+
export interface ToolingButton {
|
|
22
|
+
/** The label of the button. */
|
|
23
|
+
text: string;
|
|
24
|
+
/** The callback action - always `TOOLING_ACTION`. */
|
|
25
|
+
action: string;
|
|
26
|
+
/** The choice and the request ID, e.g. `yes-biome-<hash>`. */
|
|
27
|
+
targetId: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ToolingTarget {
|
|
30
|
+
choice: ToolingChoice;
|
|
31
|
+
requestId: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The canonical request ID of one proposal.
|
|
35
|
+
*
|
|
36
|
+
* The request ID is the correlation key: both channels send the same ID,
|
|
37
|
+
* and the first answer wins. It only holds hex characters and dashes so it
|
|
38
|
+
* survives the "_" split of the callback data.
|
|
39
|
+
*/
|
|
40
|
+
export declare function buildToolingRequestId(userKey: string, workspaceRoot: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* The key of the user the proposal is sent to.
|
|
43
|
+
*
|
|
44
|
+
* The identity is hashed: the store holds the key of a user, never the id
|
|
45
|
+
* of the user.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildToolingUserKey(identity: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* The two buttons of the proposal.
|
|
50
|
+
*/
|
|
51
|
+
export declare function buildToolingButtons(requestId: string): ToolingButton[];
|
|
52
|
+
/**
|
|
53
|
+
* Read the choice and the request ID out of a callback target.
|
|
54
|
+
*
|
|
55
|
+
* A target that does not belong to the proposal returns `null` - a click on
|
|
56
|
+
* a foreign button must never resolve a preference.
|
|
57
|
+
*/
|
|
58
|
+
export declare function parseToolingTarget(targetId: string | undefined): ToolingTarget | null;
|
|
59
|
+
/**
|
|
60
|
+
* The wording of the proposal.
|
|
61
|
+
*/
|
|
62
|
+
export declare function buildToolingProposalMessage(context: ToolingContext): string;
|
|
63
|
+
/**
|
|
64
|
+
* The instruction the agent receives after a "Yes".
|
|
65
|
+
*
|
|
66
|
+
* The agent does the repository work: the harness only records the
|
|
67
|
+
* decision and starts the implementation.
|
|
68
|
+
*/
|
|
69
|
+
export declare function buildToolingImplementationPrompt(context: ToolingContext, workspaceRoot: string): string;
|
|
70
|
+
//# sourceMappingURL=proposal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposal.d.ts","sourceRoot":"","sources":["../src/proposal.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC,8BAA8B;AAC9B,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,IAAI,CAAC;AAEzC,qDAAqD;AACrD,MAAM,MAAM,iBAAiB,GAAG,cAAc,GAAG,mBAAmB,CAAC;AAErE,MAAM,WAAW,aAAa;IAC7B,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC7B,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CAClB;AAMD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAEpF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI5D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,EAAE,CAatE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,GAAG,IAAI,CAKrF;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAwB3E;AAED;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAC/C,OAAO,EAAE,cAAc,EACvB,aAAa,EAAE,MAAM,GACnB,MAAM,CAoCR"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tooling proposal: request IDs, buttons and the wording.
|
|
3
|
+
*
|
|
4
|
+
* The proposal is a decision of its own. It never travels through the
|
|
5
|
+
* task-approval path, because a "No" there pauses the work and a "Yes"
|
|
6
|
+
* there resumes it - neither belongs to a tooling preference.
|
|
7
|
+
*/
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
/**
|
|
10
|
+
* The callback action of the proposal.
|
|
11
|
+
*
|
|
12
|
+
* The callback data is parsed by splitting on "_", so an action must be a
|
|
13
|
+
* single token: an action that carries an underscore would be read as the
|
|
14
|
+
* action up to that underscore, and the rest as the target.
|
|
15
|
+
*/
|
|
16
|
+
export const TOOLING_ACTION = "biome";
|
|
17
|
+
function shortHash(value, length = 16) {
|
|
18
|
+
return createHash("sha256").update(value).digest("hex").slice(0, length);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The canonical request ID of one proposal.
|
|
22
|
+
*
|
|
23
|
+
* The request ID is the correlation key: both channels send the same ID,
|
|
24
|
+
* and the first answer wins. It only holds hex characters and dashes so it
|
|
25
|
+
* survives the "_" split of the callback data.
|
|
26
|
+
*/
|
|
27
|
+
export function buildToolingRequestId(userKey, workspaceRoot) {
|
|
28
|
+
return `biome-${shortHash(`${userKey} ${workspaceRoot}`)}`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The key of the user the proposal is sent to.
|
|
32
|
+
*
|
|
33
|
+
* The identity is hashed: the store holds the key of a user, never the id
|
|
34
|
+
* of the user.
|
|
35
|
+
*/
|
|
36
|
+
export function buildToolingUserKey(identity) {
|
|
37
|
+
const trimmed = identity.trim();
|
|
38
|
+
if (!trimmed)
|
|
39
|
+
return "default";
|
|
40
|
+
return `u-${shortHash(`user:${trimmed}`)}`;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The two buttons of the proposal.
|
|
44
|
+
*/
|
|
45
|
+
export function buildToolingButtons(requestId) {
|
|
46
|
+
return [
|
|
47
|
+
{
|
|
48
|
+
text: "Yes - use Biome.js",
|
|
49
|
+
action: TOOLING_ACTION,
|
|
50
|
+
targetId: `yes-${requestId}`,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
text: "No - keep the current tools",
|
|
54
|
+
action: TOOLING_ACTION,
|
|
55
|
+
targetId: `no-${requestId}`,
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Read the choice and the request ID out of a callback target.
|
|
61
|
+
*
|
|
62
|
+
* A target that does not belong to the proposal returns `null` - a click on
|
|
63
|
+
* a foreign button must never resolve a preference.
|
|
64
|
+
*/
|
|
65
|
+
export function parseToolingTarget(targetId) {
|
|
66
|
+
if (!targetId)
|
|
67
|
+
return null;
|
|
68
|
+
const match = /^(yes|no)-(.+)$/.exec(targetId);
|
|
69
|
+
if (!match)
|
|
70
|
+
return null;
|
|
71
|
+
return { choice: match[1], requestId: match[2] };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The wording of the proposal.
|
|
75
|
+
*/
|
|
76
|
+
export function buildToolingProposalMessage(context) {
|
|
77
|
+
const frameworks = [];
|
|
78
|
+
if (context.isNextJs)
|
|
79
|
+
frameworks.push("Next.js");
|
|
80
|
+
if (context.isReact && !context.isNextJs)
|
|
81
|
+
frameworks.push("React");
|
|
82
|
+
const tools = [];
|
|
83
|
+
if (context.usesEslint)
|
|
84
|
+
tools.push("ESLint");
|
|
85
|
+
if (context.usesPrettier)
|
|
86
|
+
tools.push("Prettier");
|
|
87
|
+
const lines = [];
|
|
88
|
+
lines.push(frameworks.length > 0
|
|
89
|
+
? `This workspace looks like a ${frameworks.join(" + ")} project that still uses ${tools.join(" and ")}.`
|
|
90
|
+
: `This workspace looks like a JavaScript/TypeScript project that still uses ${tools.join(" and ")}.`);
|
|
91
|
+
lines.push("");
|
|
92
|
+
lines.push("Biome.js can replace both: one tool for linting, formatting and import order.");
|
|
93
|
+
lines.push("");
|
|
94
|
+
lines.push(`Detected: ${tools.join(", ")}${context.packageManager ? ` - ${context.packageManager}` : ""}`);
|
|
95
|
+
lines.push("");
|
|
96
|
+
lines.push("Yes adds Biome and migrates the lint/format setup here. No keeps the current tools. Nothing changes until you answer.");
|
|
97
|
+
return lines.join("\n");
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The instruction the agent receives after a "Yes".
|
|
101
|
+
*
|
|
102
|
+
* The agent does the repository work: the harness only records the
|
|
103
|
+
* decision and starts the implementation.
|
|
104
|
+
*/
|
|
105
|
+
export function buildToolingImplementationPrompt(context, workspaceRoot) {
|
|
106
|
+
const frameworks = [];
|
|
107
|
+
if (context.isNextJs)
|
|
108
|
+
frameworks.push("Next.js");
|
|
109
|
+
if (context.isReact && !context.isNextJs)
|
|
110
|
+
frameworks.push("React");
|
|
111
|
+
const manager = context.packageManager;
|
|
112
|
+
let install = "install it as a dev dependency with the package manager of the workspace";
|
|
113
|
+
if (manager === "npm") {
|
|
114
|
+
install = "install it with npm install --save-dev";
|
|
115
|
+
}
|
|
116
|
+
else if (manager) {
|
|
117
|
+
install = `install it with ${manager} add --save-dev`;
|
|
118
|
+
}
|
|
119
|
+
const lines = [];
|
|
120
|
+
lines.push(`The user chose to use Biome.js in this workspace (${workspaceRoot}). Implement it now.`);
|
|
121
|
+
lines.push("");
|
|
122
|
+
lines.push("1. Add Biome to the dev dependencies: " + install + " @biomejs/biome.");
|
|
123
|
+
lines.push("2. Add a biome.json that fits the project:");
|
|
124
|
+
if (frameworks.length > 0) {
|
|
125
|
+
lines.push(` - enable the ${frameworks.join(" and ")} rules,`);
|
|
126
|
+
}
|
|
127
|
+
lines.push(" - enable the formatter, the linter and the import organizer,");
|
|
128
|
+
lines.push(" - keep the settings that match the existing code style (indentation, quotes, semicolons).");
|
|
129
|
+
lines.push("3. Replace the lint and format scripts in package.json with the Biome equivalents (biome check, biome format, biome ci).");
|
|
130
|
+
lines.push("4. Migrate the ESLint and Prettier configuration that Biome replaces and remove the files Biome fully replaces.");
|
|
131
|
+
lines.push("5. Keep the type check and the tests as they are - Biome does not replace them.");
|
|
132
|
+
lines.push("6. Run the Biome check, fix what it reports in the files you touched, and report the result.");
|
|
133
|
+
lines.push("");
|
|
134
|
+
lines.push("Do not touch files outside this workspace and do not change the public behaviour of the code.");
|
|
135
|
+
return lines.join("\n");
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=proposal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposal.js","sourceRoot":"","sources":["../src/proposal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pending proposals of this session.
|
|
3
|
+
*
|
|
4
|
+
* The first answer wins: a second click on the other button changes
|
|
5
|
+
* nothing. The registry is in memory only - a proposal that was never
|
|
6
|
+
* answered simply disappears with the session.
|
|
7
|
+
*/
|
|
8
|
+
import type { ToolingChoice, ToolingPreference } from "./proposal.js";
|
|
9
|
+
export interface ToolingRequest {
|
|
10
|
+
/** The canonical request ID of the proposal. */
|
|
11
|
+
requestId: string;
|
|
12
|
+
/** The workspace the proposal belongs to. */
|
|
13
|
+
workspaceRoot: string;
|
|
14
|
+
/** The user the proposal was sent to. */
|
|
15
|
+
userKey: string;
|
|
16
|
+
/** The tooling facts of the workspace. */
|
|
17
|
+
frameworks: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface ToolingResolution {
|
|
20
|
+
choice: ToolingChoice;
|
|
21
|
+
preference: ToolingPreference;
|
|
22
|
+
channel?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare class ToolingRequestRegistry {
|
|
25
|
+
private readonly pending;
|
|
26
|
+
private readonly resolved;
|
|
27
|
+
/**
|
|
28
|
+
* Register a proposal. A request ID that is already known is refused.
|
|
29
|
+
*/
|
|
30
|
+
register(request: ToolingRequest): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Is the request still waiting for an answer?
|
|
33
|
+
*/
|
|
34
|
+
has(requestId: string): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Claim a request for an answer.
|
|
37
|
+
*
|
|
38
|
+
* The claim removes the request, so a second click finds nothing and the
|
|
39
|
+
* first answer stays the one that counts.
|
|
40
|
+
*/
|
|
41
|
+
claim(requestId: string, choice: ToolingChoice, channel?: string): {
|
|
42
|
+
request: ToolingRequest;
|
|
43
|
+
resolution: ToolingResolution;
|
|
44
|
+
} | null;
|
|
45
|
+
/**
|
|
46
|
+
* The answer of a request that was already resolved.
|
|
47
|
+
*/
|
|
48
|
+
resolutionOf(requestId: string): ToolingResolution | undefined;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEtE,MAAM,WAAW,cAAc;IAC9B,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,aAAa,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IACjC,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,sBAAsB;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAC7D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwC;IAEjE;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAMzC;IAED;;OAEG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE9B;IAED;;;;;OAKG;IACH,KAAK,CACJ,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,MAAM,GACd;QAAE,OAAO,EAAE,cAAc,CAAC;QAAC,UAAU,EAAE,iBAAiB,CAAA;KAAE,GAAG,IAAI,CAWnE;IAED;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAE7D;CACD"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pending proposals of this session.
|
|
3
|
+
*
|
|
4
|
+
* The first answer wins: a second click on the other button changes
|
|
5
|
+
* nothing. The registry is in memory only - a proposal that was never
|
|
6
|
+
* answered simply disappears with the session.
|
|
7
|
+
*/
|
|
8
|
+
export class ToolingRequestRegistry {
|
|
9
|
+
pending = new Map();
|
|
10
|
+
resolved = new Map();
|
|
11
|
+
/**
|
|
12
|
+
* Register a proposal. A request ID that is already known is refused.
|
|
13
|
+
*/
|
|
14
|
+
register(request) {
|
|
15
|
+
if (this.pending.has(request.requestId) || this.resolved.has(request.requestId)) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
this.pending.set(request.requestId, request);
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Is the request still waiting for an answer?
|
|
23
|
+
*/
|
|
24
|
+
has(requestId) {
|
|
25
|
+
return this.pending.has(requestId);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Claim a request for an answer.
|
|
29
|
+
*
|
|
30
|
+
* The claim removes the request, so a second click finds nothing and the
|
|
31
|
+
* first answer stays the one that counts.
|
|
32
|
+
*/
|
|
33
|
+
claim(requestId, choice, channel) {
|
|
34
|
+
const request = this.pending.get(requestId);
|
|
35
|
+
if (!request)
|
|
36
|
+
return null;
|
|
37
|
+
this.pending.delete(requestId);
|
|
38
|
+
const resolution = {
|
|
39
|
+
choice,
|
|
40
|
+
preference: choice === "yes" ? "prefer_biome" : "use_project_tools",
|
|
41
|
+
...(channel ? { channel } : {}),
|
|
42
|
+
};
|
|
43
|
+
this.resolved.set(requestId, resolution);
|
|
44
|
+
return { request, resolution };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The answer of a request that was already resolved.
|
|
48
|
+
*/
|
|
49
|
+
resolutionOf(requestId) {
|
|
50
|
+
return this.resolved.get(requestId);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAqBH,MAAM,OAAO,sBAAsB;IACjB,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAC;IAC5C,QAAQ,GAAG,IAAI,GAAG,EAA6B,CAAC;IAEjE;;OAEG;IACH,QAAQ,CAAC,OAAuB;QAC/B,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACjF,OAAO,KAAK,CAAC;QACd,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;OAEG;IACH,GAAG,CAAC,SAAiB;QACpB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACpC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CACJ,SAAiB,EACjB,MAAqB,EACrB,OAAgB;QAEhB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC1B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC/B,MAAM,UAAU,GAAsB;YACrC,MAAM;YACN,UAAU,EAAE,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,mBAAmB;YACnE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/B,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QACzC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,SAAiB;QAC7B,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC;CACD"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The saved tooling preference of a user in a workspace.
|
|
3
|
+
*
|
|
4
|
+
* The store is a plain JSON file under the harness runtime directory: it
|
|
5
|
+
* works in every runtime (a SQLite file would not - `node:sqlite` is
|
|
6
|
+
* missing in some of them) and it stays readable for the user.
|
|
7
|
+
*/
|
|
8
|
+
import type { ToolingPreference } from "./proposal.js";
|
|
9
|
+
export interface ToolingPreferenceRecord {
|
|
10
|
+
/** The saved decision, when the user answered. */
|
|
11
|
+
decision?: ToolingPreference;
|
|
12
|
+
/** When the proposal was sent. */
|
|
13
|
+
askedAt?: string;
|
|
14
|
+
/** When the user answered. */
|
|
15
|
+
decidedAt?: string;
|
|
16
|
+
/** The request ID of the proposal that was sent. */
|
|
17
|
+
requestId?: string;
|
|
18
|
+
/** The workspace the record belongs to. */
|
|
19
|
+
workspaceRoot?: string;
|
|
20
|
+
/** The channel the answer came from. */
|
|
21
|
+
channel?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The key of one record: the user and the workspace.
|
|
25
|
+
*/
|
|
26
|
+
export declare function toolingPreferenceKey(userKey: string, workspaceRoot: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* The runtime directory of the harness.
|
|
29
|
+
*/
|
|
30
|
+
export declare function harnessRuntimeDir(): string;
|
|
31
|
+
export declare class ToolingPreferenceStore {
|
|
32
|
+
private readonly filePath;
|
|
33
|
+
constructor(filePath: string);
|
|
34
|
+
/**
|
|
35
|
+
* The default store: `~/.pi-harness-runtime/tooling-preference.json`.
|
|
36
|
+
*/
|
|
37
|
+
static defaultFilePath(): string;
|
|
38
|
+
/**
|
|
39
|
+
* The record of one user in one workspace.
|
|
40
|
+
*/
|
|
41
|
+
read(userKey: string, workspaceRoot: string): ToolingPreferenceRecord | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Remember that the proposal was sent.
|
|
44
|
+
*/
|
|
45
|
+
markAsked(userKey: string, workspaceRoot: string, requestId: string, now?: Date): void;
|
|
46
|
+
/**
|
|
47
|
+
* Save the answer of the user.
|
|
48
|
+
*/
|
|
49
|
+
recordDecision(userKey: string, workspaceRoot: string, decision: ToolingPreference, requestId: string, channel?: string, now?: Date): void;
|
|
50
|
+
private load;
|
|
51
|
+
private save;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* May the proposal be sent again?
|
|
55
|
+
*
|
|
56
|
+
* A workspace that was asked and never answered is asked again after the
|
|
57
|
+
* cooldown - the user may have missed it. A workspace with a decision is
|
|
58
|
+
* never asked again.
|
|
59
|
+
*/
|
|
60
|
+
export declare function shouldAskAgain(record: ToolingPreferenceRecord | undefined, cooldownMs: number, now?: Date): boolean;
|
|
61
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD,MAAM,WAAW,uBAAuB;IACvC,kDAAkD;IAClD,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,kCAAkC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAQD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAEnF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAI1C;AAED,qBAAa,sBAAsB;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAArC,YAA6B,QAAQ,EAAE,MAAM,EAAI;IAEjD;;OAEG;IACH,MAAM,CAAC,eAAe,IAAI,MAAM,CAE/B;IAED;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS,CAGhF;IAED;;OAEG;IACH,SAAS,CACR,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,IAAiB,GACpB,IAAI,CAWN;IAED;;OAEG;IACH,cAAc,CACb,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,iBAAiB,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,EAChB,GAAG,GAAE,IAAiB,GACpB,IAAI,CAcN;IAED,OAAO,CAAC,IAAI;IAaZ,OAAO,CAAC,IAAI;CAYZ;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC7B,MAAM,EAAE,uBAAuB,GAAG,SAAS,EAC3C,UAAU,EAAE,MAAM,EAClB,GAAG,GAAE,IAAiB,GACpB,OAAO,CAOT"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The saved tooling preference of a user in a workspace.
|
|
3
|
+
*
|
|
4
|
+
* The store is a plain JSON file under the harness runtime directory: it
|
|
5
|
+
* works in every runtime (a SQLite file would not - `node:sqlite` is
|
|
6
|
+
* missing in some of them) and it stays readable for the user.
|
|
7
|
+
*/
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
|
+
import { dirname, join } from "node:path";
|
|
12
|
+
function shortHash(value, length = 16) {
|
|
13
|
+
return createHash("sha256").update(value).digest("hex").slice(0, length);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The key of one record: the user and the workspace.
|
|
17
|
+
*/
|
|
18
|
+
export function toolingPreferenceKey(userKey, workspaceRoot) {
|
|
19
|
+
return `${userKey}::${shortHash(workspaceRoot)}`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The runtime directory of the harness.
|
|
23
|
+
*/
|
|
24
|
+
export function harnessRuntimeDir() {
|
|
25
|
+
const configured = process.env.PI_HARNESS_HOME?.trim();
|
|
26
|
+
if (configured)
|
|
27
|
+
return configured;
|
|
28
|
+
return join(homedir(), ".pi-harness-runtime");
|
|
29
|
+
}
|
|
30
|
+
export class ToolingPreferenceStore {
|
|
31
|
+
filePath;
|
|
32
|
+
constructor(filePath) {
|
|
33
|
+
this.filePath = filePath;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The default store: `~/.pi-harness-runtime/tooling-preference.json`.
|
|
37
|
+
*/
|
|
38
|
+
static defaultFilePath() {
|
|
39
|
+
return join(harnessRuntimeDir(), "tooling-preference.json");
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The record of one user in one workspace.
|
|
43
|
+
*/
|
|
44
|
+
read(userKey, workspaceRoot) {
|
|
45
|
+
const data = this.load();
|
|
46
|
+
return data[toolingPreferenceKey(userKey, workspaceRoot)];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Remember that the proposal was sent.
|
|
50
|
+
*/
|
|
51
|
+
markAsked(userKey, workspaceRoot, requestId, now = new Date()) {
|
|
52
|
+
const key = toolingPreferenceKey(userKey, workspaceRoot);
|
|
53
|
+
const data = this.load();
|
|
54
|
+
const existing = data[key] ?? {};
|
|
55
|
+
data[key] = {
|
|
56
|
+
...existing,
|
|
57
|
+
askedAt: now.toISOString(),
|
|
58
|
+
requestId,
|
|
59
|
+
workspaceRoot,
|
|
60
|
+
};
|
|
61
|
+
this.save(data);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Save the answer of the user.
|
|
65
|
+
*/
|
|
66
|
+
recordDecision(userKey, workspaceRoot, decision, requestId, channel, now = new Date()) {
|
|
67
|
+
const key = toolingPreferenceKey(userKey, workspaceRoot);
|
|
68
|
+
const data = this.load();
|
|
69
|
+
const existing = data[key] ?? {};
|
|
70
|
+
data[key] = {
|
|
71
|
+
...existing,
|
|
72
|
+
decision,
|
|
73
|
+
decidedAt: now.toISOString(),
|
|
74
|
+
askedAt: existing.askedAt ?? now.toISOString(),
|
|
75
|
+
requestId,
|
|
76
|
+
workspaceRoot,
|
|
77
|
+
...(channel ? { channel } : {}),
|
|
78
|
+
};
|
|
79
|
+
this.save(data);
|
|
80
|
+
}
|
|
81
|
+
load() {
|
|
82
|
+
if (!existsSync(this.filePath))
|
|
83
|
+
return {};
|
|
84
|
+
try {
|
|
85
|
+
const parsed = JSON.parse(readFileSync(this.filePath, "utf8"));
|
|
86
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
87
|
+
return {};
|
|
88
|
+
return parsed;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// A broken store must not stop the harness: the proposal is
|
|
92
|
+
// simply asked again.
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
save(data) {
|
|
97
|
+
try {
|
|
98
|
+
mkdirSync(dirname(this.filePath), { recursive: true });
|
|
99
|
+
const temporary = `${this.filePath}.tmp`;
|
|
100
|
+
writeFileSync(temporary, `${JSON.stringify(data, null, 2)}\n`, "utf8");
|
|
101
|
+
// The rename keeps a half written file from being read.
|
|
102
|
+
renameSync(temporary, this.filePath);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// A store that cannot be written is a lost preference, not a
|
|
106
|
+
// broken harness.
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* May the proposal be sent again?
|
|
112
|
+
*
|
|
113
|
+
* A workspace that was asked and never answered is asked again after the
|
|
114
|
+
* cooldown - the user may have missed it. A workspace with a decision is
|
|
115
|
+
* never asked again.
|
|
116
|
+
*/
|
|
117
|
+
export function shouldAskAgain(record, cooldownMs, now = new Date()) {
|
|
118
|
+
if (!record)
|
|
119
|
+
return true;
|
|
120
|
+
if (record.decision)
|
|
121
|
+
return false;
|
|
122
|
+
if (!record.askedAt)
|
|
123
|
+
return true;
|
|
124
|
+
const askedAt = Date.parse(record.askedAt);
|
|
125
|
+
if (Number.isNaN(askedAt))
|
|
126
|
+
return true;
|
|
127
|
+
return now.getTime() - askedAt >= cooldownMs;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAoB1C,SAAS,SAAS,CAAC,KAAa,EAAE,MAAM,GAAG,EAAE;IAC5C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AAC1E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAe,EAAE,aAAqB;IAC1E,OAAO,GAAG,OAAO,KAAK,SAAS,CAAC,aAAa,CAAC,EAAE,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAChC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC;IACvD,IAAI,UAAU;QAAE,OAAO,UAAU,CAAC;IAClC,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,qBAAqB,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,OAAO,sBAAsB;IACL,QAAQ;IAArC,YAA6B,QAAgB;wBAAhB,QAAQ;IAAW,CAAC;IAEjD;;OAEG;IACH,MAAM,CAAC,eAAe;QACrB,OAAO,IAAI,CAAC,iBAAiB,EAAE,EAAE,yBAAyB,CAAC,CAAC;IAC7D,CAAC;IAED;;OAEG;IACH,IAAI,CAAC,OAAe,EAAE,aAAqB;QAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED;;OAEG;IACH,SAAS,CACR,OAAe,EACf,aAAqB,EACrB,SAAiB,EACjB,GAAG,GAAS,IAAI,IAAI,EAAE;QAEtB,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACjC,IAAI,CAAC,GAAG,CAAC,GAAG;YACX,GAAG,QAAQ;YACX,OAAO,EAAE,GAAG,CAAC,WAAW,EAAE;YAC1B,SAAS;YACT,aAAa;SACb,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,cAAc,CACb,OAAe,EACf,aAAqB,EACrB,QAA2B,EAC3B,SAAiB,EACjB,OAAgB,EAChB,GAAG,GAAS,IAAI,IAAI,EAAE;QAEtB,MAAM,GAAG,GAAG,oBAAoB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACjC,IAAI,CAAC,GAAG,CAAC,GAAG;YACX,GAAG,QAAQ;YACX,QAAQ;YACR,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE;YAC5B,OAAO,EAAE,QAAQ,CAAC,OAAO,IAAI,GAAG,CAAC,WAAW,EAAE;YAC9C,SAAS;YACT,aAAa;YACb,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/B,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC;IAEO,IAAI;QACX,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,OAAO,EAAE,CAAC;QAC1C,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAY,CAAC;YAC1E,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;gBAAE,OAAO,EAAE,CAAC;YAC9E,OAAO,MAAmB,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACR,4DAA4D;YAC5D,sBAAsB;YACtB,OAAO,EAAE,CAAC;QACX,CAAC;IACF,CAAC;IAEO,IAAI,CAAC,IAAe;QAC3B,IAAI,CAAC;YACJ,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACvD,MAAM,SAAS,GAAG,GAAG,IAAI,CAAC,QAAQ,MAAM,CAAC;YACzC,aAAa,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACvE,wDAAwD;YACxD,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACR,6DAA6D;YAC7D,kBAAkB;QACnB,CAAC;IACF,CAAC;CACD;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC7B,MAA2C,EAC3C,UAAkB,EAClB,GAAG,GAAS,IAAI,IAAI,EAAE;IAEtB,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,MAAM,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IAClC,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,GAAG,CAAC,OAAO,EAAE,GAAG,OAAO,IAAI,UAAU,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pi-harness/tooling-preference",
|
|
3
|
+
"version": "1.1.405",
|
|
4
|
+
"description": "pi-harness-runtime — JS/TS tooling preference (Biome vs ESLint/Prettier) proposal",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"test": "bun test"
|
|
20
|
+
}
|
|
21
|
+
}
|