@intentic/sandbox-contract 1.235.0 → 1.236.0
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/chores/chores.d.ts.map +1 -1
- package/dist/chores/chores.js +2 -1
- package/dist/chores/chores.js.map +1 -1
- package/dist/chores/index.d.ts +1 -0
- package/dist/chores/index.d.ts.map +1 -1
- package/dist/chores/index.js +1 -0
- package/dist/chores/index.js.map +1 -1
- package/dist/chores/probes.d.ts.map +1 -1
- package/dist/chores/probes.js +4 -3
- package/dist/chores/probes.js.map +1 -1
- package/dist/chores/workspace-scope.d.ts +4 -0
- package/dist/chores/workspace-scope.d.ts.map +1 -0
- package/dist/chores/workspace-scope.js +4 -0
- package/dist/chores/workspace-scope.js.map +1 -0
- package/dist/contracts/extensions.contract.d.ts +1 -2
- package/dist/contracts/extensions.contract.d.ts.map +1 -1
- package/dist/contracts/extensions.contract.js +5 -5
- package/dist/contracts/extensions.contract.js.map +1 -1
- package/dist/contracts/workspace.contract.d.ts +1 -0
- package/dist/contracts/workspace.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.js +2 -2
- package/dist/contracts/workspace.contract.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/ingress-protocol.d.ts +16 -0
- package/dist/ingress-protocol.d.ts.map +1 -0
- package/dist/ingress-protocol.js +263 -0
- package/dist/ingress-protocol.js.map +1 -0
- package/dist/schemas/agents.d.ts.map +1 -1
- package/dist/schemas/agents.js +5 -5
- package/dist/schemas/agents.js.map +1 -1
- package/dist/schemas/extension-updates.d.ts +2 -3
- package/dist/schemas/extension-updates.d.ts.map +1 -1
- package/dist/schemas/extension-updates.js +4 -3
- package/dist/schemas/extension-updates.js.map +1 -1
- package/dist/schemas/workspace-tree.d.ts +1 -0
- package/dist/schemas/workspace-tree.d.ts.map +1 -1
- package/dist/schemas/workspace-tree.js +8 -1
- package/dist/schemas/workspace-tree.js.map +1 -1
- package/package.json +4 -4
- package/src/chores/chores.ts +2 -1
- package/src/chores/index.ts +1 -0
- package/src/chores/probes.test.ts +12 -0
- package/src/chores/probes.ts +5 -3
- package/src/chores/workspace-scope.ts +12 -0
- package/src/contracts/extensions.contract.ts +7 -6
- package/src/contracts/workspace.contract.ts +3 -2
- package/src/events.ts +2 -2
- package/src/ingress-protocol.test.ts +509 -0
- package/src/ingress-protocol.ts +574 -0
- package/src/schemas/agents.ts +20 -21
- package/src/schemas/extension-updates.ts +9 -7
- package/src/schemas/workspace-tree.ts +13 -4
- package/src/tunnel-ids.ts +4 -4
package/src/chores/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ export { updateBrief } from "./extension-update.js";
|
|
|
8
8
|
export type { UpdateBrief } from "./extension-update.js";
|
|
9
9
|
export { PROBES, probeSpec } from "./probes.js";
|
|
10
10
|
export type { ProbeSpec } from "./probes.js";
|
|
11
|
+
export { WORKSPACE_ROOT_EXCLUDE_ENV } from "./workspace-scope.js";
|
|
11
12
|
export { componentStem, frameworksOf, IDIOM_RULES, idiomRule, normalizePath, UI_FRAMEWORKS, usesTailwind } from "./stack.js";
|
|
12
13
|
export type { IdiomRule, UiFramework } from "./stack.js";
|
|
13
14
|
export { assessChore, assessReport, ledgerKey, unseenVerdicts } from "./verdict.js";
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { choreById } from "./chores.js";
|
|
2
3
|
import { probeSpec } from "./probes.js";
|
|
3
4
|
import { IDIOM_RULES } from "./stack.js";
|
|
5
|
+
import { WORKSPACE_ROOT_JSCPD_EXCLUDE_ARG, WORKSPACE_ROOT_RG_EXCLUDE_ARG } from "./workspace-scope.js";
|
|
4
6
|
|
|
5
7
|
/* The parsers are the part of this library that faces someone else's output, so they are tested the way that
|
|
6
8
|
* output actually arrives: real shapes, then the shapes that have historically broken things, a tool that
|
|
@@ -143,6 +145,11 @@ describe(`knip`, () => {
|
|
|
143
145
|
});
|
|
144
146
|
|
|
145
147
|
describe(`jscpd`, () => {
|
|
148
|
+
test(`the root-scoped command carries the reference-shelf prune argument`, () => {
|
|
149
|
+
expect(probeSpec(`jscpd`).command).toContain(WORKSPACE_ROOT_JSCPD_EXCLUDE_ARG);
|
|
150
|
+
expect(choreById(`duplication`)?.automation?.guard).toContain(WORKSPACE_ROOT_JSCPD_EXCLUDE_ARG);
|
|
151
|
+
});
|
|
152
|
+
|
|
146
153
|
test(`takes the percentage of scanned lines and the biggest clones, longest first`, () => {
|
|
147
154
|
const facts = parse(
|
|
148
155
|
`jscpd`,
|
|
@@ -322,6 +329,11 @@ describe(`ui`, () => {
|
|
|
322
329
|
describe(`the sweep's composed command`, () => {
|
|
323
330
|
const stages = (): string[] => probeSpec(`ui`).command.split(`; `);
|
|
324
331
|
|
|
332
|
+
test(`both ripgrep entry points carry the root-scoped prune argument`, () => {
|
|
333
|
+
expect(probeSpec(`ui`).available).toContain(WORKSPACE_ROOT_RG_EXCLUDE_ARG);
|
|
334
|
+
expect(probeSpec(`ui`).command.split(WORKSPACE_ROOT_RG_EXCLUDE_ARG)).toHaveLength(3 + IDIOM_RULES.length);
|
|
335
|
+
});
|
|
336
|
+
|
|
325
337
|
/* Given no path, ripgrep searches STDIN whenever stdin is not a TTY, which is exactly how a probe is spawned.
|
|
326
338
|
* The sweep exited 0, printed its marker and matched nothing, in every repository, forever, which the marker
|
|
327
339
|
* line cannot catch because the sweep really did run. It reproduces from a child process and never from an
|
package/src/chores/probes.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
UI_FRAMEWORKS,
|
|
11
11
|
TAILWIND_PACKAGES,
|
|
12
12
|
} from "./stack.js";
|
|
13
|
+
import { WORKSPACE_ROOT_JSCPD_EXCLUDE_ARG, WORKSPACE_ROOT_RG_EXCLUDE_ARG } from "./workspace-scope.js";
|
|
13
14
|
|
|
14
15
|
/* THE PROBES, the measurements that cost a subprocess, declared once so the daemon that runs them and the panel
|
|
15
16
|
* that explains them cannot disagree about what "outdated" meant.
|
|
@@ -348,7 +349,8 @@ const RULE_FILE_LIMIT = 500;
|
|
|
348
349
|
* path reaches the chores no matter which tool produced it. */
|
|
349
350
|
const SCAN_ROOT = `.`;
|
|
350
351
|
|
|
351
|
-
const globArgs = (globs: readonly string[]): string =>
|
|
352
|
+
const globArgs = (globs: readonly string[]): string =>
|
|
353
|
+
[...[...globs, ...SCAN_IGNORES].map((glob) => `-g '${glob}'`), WORKSPACE_ROOT_RG_EXCLUDE_ARG].join(` `);
|
|
352
354
|
|
|
353
355
|
// `path:count` from `rg --count-matches`, normalised. Split at the LAST colon: a path may contain one, a count is
|
|
354
356
|
// always the digits at the end.
|
|
@@ -526,7 +528,7 @@ export const PROBES: readonly ProbeSpec[] = [
|
|
|
526
528
|
// `--threshold 100` so jscpd never fails the command on its own opinion of what is too much duplication,
|
|
527
529
|
// that judgement is the chore's, made from the percentage, not the tool's exit code.
|
|
528
530
|
command:
|
|
529
|
-
`pnpm dlx jscpd --reporters json --output ${JSCPD_DIR} --min-lines 12 --threshold 100 . >/dev/null 2>&1; ` +
|
|
531
|
+
`pnpm dlx jscpd ${WORKSPACE_ROOT_JSCPD_EXCLUDE_ARG} --reporters json --output ${JSCPD_DIR} --min-lines 12 --threshold 100 . >/dev/null 2>&1; ` +
|
|
530
532
|
`cat ${JSCPD_DIR}/jscpd-report.json 2>/dev/null`,
|
|
531
533
|
parse: parseJscpd,
|
|
532
534
|
},
|
|
@@ -576,7 +578,7 @@ export const PROBES: readonly ProbeSpec[] = [
|
|
|
576
578
|
// Any manifest in the repo declaring a UI framework or Tailwind, not just the root's, a monorepo keeps
|
|
577
579
|
// React in the app package and the root manifest is a handful of build tools.
|
|
578
580
|
available:
|
|
579
|
-
`rg -l --no-messages -g '**/package.json' -g '!**/node_modules/**' ` +
|
|
581
|
+
`rg -l --no-messages -g '**/package.json' -g '!**/node_modules/**' ${WORKSPACE_ROOT_RG_EXCLUDE_ARG} ` +
|
|
580
582
|
`-e '[\\x22](${[...UI_FRAMEWORKS.flatMap((framework) => framework.packages), ...TAILWIND_PACKAGES].join(`|`)})[\\x22]\\s*:' . >/dev/null`,
|
|
581
583
|
unavailable: `no package here declares a UI framework or Tailwind`,
|
|
582
584
|
command: scanCommand(),
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* Maintenance probes normally run inside one discovered repository, where a `refs/` directory is ordinary
|
|
2
|
+
* project content. They also run once against the workspace root, where the same first segment is the reserved
|
|
3
|
+
* reference shelf and can hold hundreds of thousands of files. The daemon sets this variable only for that
|
|
4
|
+
* root scope; shell commands opt into the matching prune argument without baking the shelf's name into the
|
|
5
|
+
* browser-safe contract package. */
|
|
6
|
+
export const WORKSPACE_ROOT_EXCLUDE_ENV = `INTENTIC_WORKSPACE_ROOT_EXCLUDE`;
|
|
7
|
+
|
|
8
|
+
// Unquoted parameter expansion is intentional: when the variable is absent it contributes zero arguments;
|
|
9
|
+
// when present, each expression expands to one whitespace-free CLI argument. The daemon supplies the value
|
|
10
|
+
// from @intentic/workspace-ignore, never from user input.
|
|
11
|
+
export const WORKSPACE_ROOT_RG_EXCLUDE_ARG = `\${${WORKSPACE_ROOT_EXCLUDE_ENV}:+--glob=!/\${${WORKSPACE_ROOT_EXCLUDE_ENV}}/**}`;
|
|
12
|
+
export const WORKSPACE_ROOT_JSCPD_EXCLUDE_ARG = `\${${WORKSPACE_ROOT_EXCLUDE_ENV}:+--ignore=\${${WORKSPACE_ROOT_EXCLUDE_ENV}}/**}`;
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
ExtensionUpdatePolicyInputSchema,
|
|
13
13
|
ExtensionUpdatePreviewSchema,
|
|
14
14
|
ExtensionUpdatesCheckedSchema,
|
|
15
|
-
|
|
15
|
+
ExtensionUsageBatchSchema,
|
|
16
16
|
WorkspaceExtensionCreatedSchema,
|
|
17
17
|
WorkspaceExtensionCreateSchema,
|
|
18
18
|
} from "../schemas/extension-updates.js";
|
|
@@ -80,16 +80,17 @@ export const extensionsContract = {
|
|
|
80
80
|
.output(OkSchema),
|
|
81
81
|
// The host reporting which declared routes it just let through. Written by the browser because that is where
|
|
82
82
|
// the permission gate runs (apiImpl.ts), the daemon sees an extension's traffic as ordinary authenticated
|
|
83
|
-
// requests and cannot tell which extension, or which declared entry, any of it belongs to.
|
|
83
|
+
// requests and cannot tell which extension, or which declared entry, any of it belongs to. Every extension's
|
|
84
|
+
// accumulated counts ride together so the bookkeeping is one request rather than a burst of them.
|
|
84
85
|
recordUsage: oc
|
|
85
86
|
.route({
|
|
86
87
|
method: "POST",
|
|
87
|
-
path: "/extensions/
|
|
88
|
-
summary: "Record what
|
|
88
|
+
path: "/extensions/usage",
|
|
89
|
+
summary: "Record what extensions just used",
|
|
89
90
|
description:
|
|
90
|
-
"
|
|
91
|
+
"One batch written by the app rather than measured by the daemon, because the permission gate runs in the browser: from the sandbox's side extension traffic is indistinguishable from anyone else's. This is how the record of which powers each extension actually exercises gets kept without one reporting request per extension.",
|
|
91
92
|
})
|
|
92
|
-
.input(
|
|
93
|
+
.input(ExtensionUsageBatchSchema)
|
|
93
94
|
.output(OkSchema),
|
|
94
95
|
/* Whether this extension is fit for somebody else to run, the checks answerable from its files alone. Read
|
|
95
96
|
* on demand rather than carried on the list: it reads the bundle off disk per extension, and it is looked at
|
|
@@ -53,13 +53,14 @@ export const workspaceContract = {
|
|
|
53
53
|
.output(WorkspaceTreeSchema),
|
|
54
54
|
// Lazy-load one directory's children, the tree returns ignored dirs (node_modules, .git, …) without children,
|
|
55
55
|
// and the client fetches them here on expand so a giant node_modules can't blow the tree walk's entry budget.
|
|
56
|
+
// Bounded depth is for consumers that need a small subtree as data rather than one explorer row at a time.
|
|
56
57
|
children: oc
|
|
57
58
|
.route({
|
|
58
59
|
method: "GET",
|
|
59
60
|
path: "/workspace/children",
|
|
60
|
-
summary: "
|
|
61
|
+
summary: "A bounded folder listing",
|
|
61
62
|
description:
|
|
62
|
-
"The entries
|
|
63
|
+
"The entries inside a folder as one flat list. Direct children are the default, which is how the explorer opens a folder the full tree walk left closed; callers that need a small subtree can ask for up to five levels without a request per directory.",
|
|
63
64
|
})
|
|
64
65
|
.input(WorkspaceChildrenQuerySchema)
|
|
65
66
|
.output(WorkspaceChildrenSchema),
|
package/src/events.ts
CHANGED
|
@@ -495,8 +495,8 @@ const PlanCardSchema = z.object({
|
|
|
495
495
|
kind: z.literal("plan").describe("The agent has written a plan and is waiting for a yes."),
|
|
496
496
|
requestId: z.string().describe("What to send back when you answer."),
|
|
497
497
|
text: z.string().describe("The plan itself."),
|
|
498
|
-
// Present when the plan
|
|
499
|
-
// file and summarised it
|
|
498
|
+
// Present when the adjacent plan prose POINTS at a document instead of being one: the model wrote the real
|
|
499
|
+
// plan to a file and summarised it there. Absent when the text already is the whole plan.
|
|
500
500
|
document: CardDocumentSchema.optional().describe("The write-up this plan refers to, when the plan itself is a pointer to one."),
|
|
501
501
|
});
|
|
502
502
|
const QuestionCardSchema = z.object({
|